<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Immae's blog</title><link href="https://www.immae.eu/" rel="alternate"></link><link href="https://www.immae.eu/blog/feed/atom/index.xml" rel="self"></link><id>https://www.immae.eu/</id><updated>2020-06-06T01:55:00+02:00</updated><entry><title>Migrate from RAID1 disk to ZFS on NixOS</title><link href="https://www.immae.eu/blog/2020/06/06/migrate-from-raid1-disk-to-zfs-on-nixos/" rel="alternate"></link><published>2020-06-06T01:55:00+02:00</published><updated>2020-06-06T01:55:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2020-06-06:/blog/2020/06/06/migrate-from-raid1-disk-to-zfs-on-nixos/</id><summary type="html">&lt;p&gt;&lt;em&gt;As of 2020-06-06 I only made those tests inside a VM (See
&lt;a href="#libvirtd"&gt;below&lt;/a&gt; if you want to play with it too). I’m not fully at
peace with the process yet to actually apply it on my server. Use at
your own risk!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Edit 2020-08-13: Adjustments to the process after …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;As of 2020-06-06 I only made those tests inside a VM (See
&lt;a href="#libvirtd"&gt;below&lt;/a&gt; if you want to play with it too). I’m not fully at
peace with the process yet to actually apply it on my server. Use at
your own risk!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Edit 2020-08-13: Adjustments to the process after some advices by Linus
Heckemann (sphalerite on freenode): the /boot partition stays outside of
zfs and some flags are set by default on the zpool.&lt;/p&gt;
&lt;p&gt;Edit 2020-08-25: The configuration was successfully applied. An issue
occured with two ZFS pools having the same name, which prevented the
system from booting. Thanks to sphalerite, BiBi and Raito_Bezarius
for their supports during the hours of debugging it took to figure out
the issue.&lt;/p&gt;
&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;I’m the happy owner of a server which holds my whole infrastructure
for more than one year now, powered by NixOS for declarative
deployments. When I installed it the first time, I didn’t know about
ZFS and all its features (see &lt;a href="https://pthree.org/2012/12/04/zfs-administration-part-i-vdevs/"&gt;there&lt;/a&gt;
if you want some examples)&lt;/p&gt;
&lt;p&gt;Since I cannot afford to reinstall everything from scratch, I had to
find a way to deploy ZFS safely (i.e. without losing redundancy).
This article explains step by step the choices I made.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;The server has a single relevant partition mounted on &lt;code&gt;/&lt;/code&gt; (the other
partitions are BIOS boot and swap, non-relevant here). This partition is
a RAID1 array, backed by two disks. The partition holding &lt;code&gt;/&lt;/code&gt; on the
underlying disks is the third one, that is &lt;code&gt;/dev/md0&lt;/code&gt; containing
&lt;code&gt;/dev/sda3&lt;/code&gt; and &lt;code&gt;/dev/sdb3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The distribution of my server is NixOS, installed remotely via
nixops. Some commands will rely on that fact below, but might be
adapted depending on your distribution (or if you don’t use
nixops)&lt;/p&gt;
&lt;p&gt;I ordrered an additional disk to my server provider
(&lt;code&gt;/dev/sdc&lt;/code&gt;). The sole purpose of this disk is to ensure
redundancy in case of failure during the process. The process itself
could be adapted to not need it if you’re confident enough. It can
be thrown away at the end of the process.&lt;/p&gt;
&lt;h2&gt;&lt;a name="libvirtd"&gt;&lt;/a&gt; Play with libvirtd&lt;/h2&gt;
&lt;p&gt;Since I didn’t want to break my server, I created a libvirtd rough
equivalent of my setup: three disk images, two of them mounted as RAID
array. Since it is a quite specific setup, I couldn’t make a fully
declarative VM handled by nixops, but I still made use of some of
nixpkgs helpers.&lt;/p&gt;
&lt;p&gt;The derivation below will produce an output with three disks image
as described above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# base_image.nix&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; system &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;currentSystem&lt;span class="p"&gt;,&lt;/span&gt; size &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;10&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt;
  &lt;span class="ss"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="ss"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="l"&gt;&amp;lt;nixpkgs/nixos/lib/eval-config.nix&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;inherit&lt;/span&gt; system&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="ss"&gt;modules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/dev/disk/by-label/root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      boot&lt;span class="o"&gt;.&lt;/span&gt;loader&lt;span class="o"&gt;.&lt;/span&gt;grub&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      boot&lt;span class="o"&gt;.&lt;/span&gt;loader&lt;span class="o"&gt;.&lt;/span&gt;grub&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;devices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/dev/vda&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/dev/vdb&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
      boot&lt;span class="o"&gt;.&lt;/span&gt;loader&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      boot&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;kernelParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;console=ttyS0,115200&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      services&lt;span class="o"&gt;.&lt;/span&gt;openssh&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      services&lt;span class="o"&gt;.&lt;/span&gt;openssh&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;startWhenNeeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      services&lt;span class="o"&gt;.&lt;/span&gt;openssh&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;extraConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;UseDNS no&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;config&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;the_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;getEnv &lt;span class="s2"&gt;&amp;quot;NIXOPS_LIBVIRTD_PUBKEY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;vmTools&lt;span class="o"&gt;.&lt;/span&gt;runInLinuxVM &lt;span class="p"&gt;(&lt;/span&gt;
  pkgs&lt;span class="o"&gt;.&lt;/span&gt;runCommand &lt;span class="s2"&gt;&amp;quot;libvirtd-image&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;memSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="ss"&gt;preVM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          mkdir $out&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          diskImage1=$out/image&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          diskImage2=$out/image2&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          diskImage3=$out/image3&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;vmTools&lt;span class="o"&gt;.&lt;/span&gt;qemu&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/qemu-img create -f qcow2 $diskImage1 &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;size&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;G&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;vmTools&lt;span class="o"&gt;.&lt;/span&gt;qemu&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/qemu-img create -f qcow2 $diskImage2 &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;size&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;G&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;vmTools&lt;span class="o"&gt;.&lt;/span&gt;qemu&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/qemu-img create -f qcow2 $diskImage3 &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;size&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;G&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          mv closure xchg/&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="ss"&gt;postVM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          mv $diskImage1 $out/disk.qcow2&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          mv $diskImage2 $out/disk2.qcow2&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          mv $diskImage3 $out/disk3.qcow2&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="ss"&gt;QEMU_OPTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;concatStringsSep &lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;-drive file=$diskImage1,if=virtio,cache=unsafe,werror=report&amp;quot;&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;-drive file=$diskImage2,if=virtio,cache=unsafe,werror=report&amp;quot;&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;-drive file=$diskImage3,if=virtio,cache=unsafe,werror=report&amp;quot;&lt;/span&gt;
      &lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="ss"&gt;buildInputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;utillinux pkgs&lt;span class="o"&gt;.&lt;/span&gt;perl pkgs&lt;span class="o"&gt;.&lt;/span&gt;kmod &lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="ss"&gt;exportReferencesGraph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;closure&amp;quot;&lt;/span&gt; config&lt;span class="o"&gt;.&lt;/span&gt;system&lt;span class="o"&gt;.&lt;/span&gt;build&lt;span class="o"&gt;.&lt;/span&gt;toplevel &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;parted&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/parted --script /dev/vda -- \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mklabel gpt \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkpart ESP fat32 8MiB 256MiB \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        set 1 boot on \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        set 1 bios_grub on \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkpart sap1 linux-swap 256MiB 512MiB \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkpart primary ext4 512MiB -1&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;parted&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/parted --script /dev/vdb -- \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mklabel gpt \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkpart ESP fat32 8MiB 256MiB \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        set 1 boot on \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        set 1 bios_grub on \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkpart sap1 linux-swap 256MiB 512MiB \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkpart primary ext4 512MiB -1&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;mdadm&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/mdadm --create /dev/md0 --metadata=0.90 --level=1 --raid-devices=2 /dev/vda3 /dev/vdb3&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      # Create an empty filesystem and mount it.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;e2fsprogs&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/sbin/mkfs.ext4 -L root /dev/md0&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;e2fsprogs&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/sbin/tune2fs -c 0 -i 0 /dev/md0&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mkdir /mnt&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mount /dev/md0 /mnt&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      export HOME=$TMPDIR&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      export NIX_STATE_DIR=$TMPDIR/state&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/etc/nixos&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      # The initrd expects these directories to exist.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mkdir /mnt/dev /mnt/proc /mnt/sys&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mount --bind /proc /mnt/proc&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mount --bind /dev /mnt/dev&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mount --bind /sys /mnt/sys&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      # Copy all paths in the closure to the filesystem.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      storePaths=$(perl &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;pathsFromGraph&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt; /tmp/xchg/closure)&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      echo &amp;quot;filling Nix store...&amp;quot;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/nix/store&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      set -f&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      cp -prd $storePaths /mnt/nix/store/&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/etc/nix&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      echo &amp;#39;build-users-group = &amp;#39; &amp;gt; /mnt/etc/nix/nix.conf&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      export USER=root&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      ## Register the paths in the Nix database.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      printRegistration=1 perl &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;pathsFromGraph&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt; /tmp/xchg/closure | \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          chroot /mnt &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;config&lt;span class="o"&gt;.&lt;/span&gt;nix&lt;span class="o"&gt;.&lt;/span&gt;package&lt;span class="o"&gt;.&lt;/span&gt;out&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/nix-store --load-db&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/nix/var/nix/profiles&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      # Create the system profile to allow nixos-rebuild to work.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      chroot /mnt &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;config&lt;span class="o"&gt;.&lt;/span&gt;nix&lt;span class="o"&gt;.&lt;/span&gt;package&lt;span class="o"&gt;.&lt;/span&gt;out&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/nix-env \&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          -p /nix/var/nix/profiles/system --set &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;config&lt;span class="o"&gt;.&lt;/span&gt;system&lt;span class="o"&gt;.&lt;/span&gt;build&lt;span class="o"&gt;.&lt;/span&gt;toplevel&lt;span class="si"&gt;}&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      # `nixos-rebuild&amp;#39; requires an /etc/NIXOS.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/etc/nixos&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      touch /mnt/etc/NIXOS&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      # `switch-to-configuration&amp;#39; requires a /bin/sh&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/bin&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      ln -s &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;config&lt;span class="o"&gt;.&lt;/span&gt;system&lt;span class="o"&gt;.&lt;/span&gt;build&lt;span class="o"&gt;.&lt;/span&gt;binsh&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/sh /mnt/bin/sh&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      # Generate the GRUB menu.&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      chroot /mnt &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;config&lt;span class="o"&gt;.&lt;/span&gt;system&lt;span class="o"&gt;.&lt;/span&gt;build&lt;span class="o"&gt;.&lt;/span&gt;toplevel&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/switch-to-configuration boot&lt;/span&gt;

&lt;span class="s s-Multiline"&gt;      mkdir -p /mnt/etc/ssh/authorized_keys.d&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      echo &amp;#39;${the_key}&amp;#39; &amp;gt; /mnt/etc/ssh/authorized_keys.d/root&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      umount /mnt/proc /mnt/dev /mnt/sys&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      umount /mnt&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;    &amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When deploying with nixops (via the libvirtd backend), you will need to
make each image available. However, nixops only handles one and only one
image, so we will need a bit of manual tasks. This is the nixops
configuration I’m using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# libvirtd.nix&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;testzfs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; pkgs&lt;span class="p"&gt;,&lt;/span&gt; lib&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;mkForce &lt;span class="s2"&gt;&amp;quot;/dev/disk/by-label/root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Serial access via virsh console (quite handy for debugging)&lt;/span&gt;
    boot&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;kernelParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;console=ttyS0,115200&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    boot&lt;span class="o"&gt;.&lt;/span&gt;loader&lt;span class="o"&gt;.&lt;/span&gt;grub&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;extraConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      terminal_output serial&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      terminal_input serial&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;    &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    boot&lt;span class="o"&gt;.&lt;/span&gt;loader&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lib&lt;span class="o"&gt;.&lt;/span&gt;mkForce &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# You need to explicitely specify the additional disk here&lt;/span&gt;
    boot&lt;span class="o"&gt;.&lt;/span&gt;loader&lt;span class="o"&gt;.&lt;/span&gt;grub&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;devices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/dev/sdb&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="ss"&gt;deployment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;targetEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;libvirtd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      libvirtd&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;baseImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; pkgs&lt;span class="o"&gt;.&lt;/span&gt;callPackage &lt;span class="l"&gt;./base_image.nix&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
      &lt;span class="c1"&gt;# Additional images need to be specified explicitely here (only the sda one will be picked by nixops)&lt;/span&gt;
      libvirtd&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;extraDevicesXML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &amp;lt;disk type=&amp;quot;file&amp;quot; device=&amp;quot;disk&amp;quot; snapshot=&amp;quot;external&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &amp;lt;driver name=&amp;quot;qemu&amp;quot; type=&amp;quot;qcow2&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &amp;lt;source file=&amp;quot;/path/to/disk2.qcow2&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &amp;lt;target dev=&amp;quot;hdb&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &amp;lt;/disk&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &amp;lt;disk type=&amp;quot;file&amp;quot; device=&amp;quot;disk&amp;quot; snapshot=&amp;quot;external&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &amp;lt;driver name=&amp;quot;qemu&amp;quot; type=&amp;quot;qcow2&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &amp;lt;source file=&amp;quot;/path/to/disk3.qcow2&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &amp;lt;target dev=&amp;quot;hdc&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        &amp;lt;/disk&amp;gt;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;# Some dummy service that writes to disk regularly&lt;/span&gt;
    systemd&lt;span class="o"&gt;.&lt;/span&gt;services&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;nag-var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Some service reading and writing to /var&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="ss"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;network.target&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="ss"&gt;wantedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;multi-user.target&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="ss"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s s-Multiline"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        #!&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;stdenv&lt;span class="o"&gt;.&lt;/span&gt;shell&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        mkdir -p /var/nagvar&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        while true; do&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;coreutils&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/date &amp;gt; /var/nagvar/last&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;          &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;pkgs&lt;span class="o"&gt;.&lt;/span&gt;coreutils&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s s-Multiline"&gt;/bin/sleep 10&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;        done&lt;/span&gt;
&lt;span class="s s-Multiline"&gt;      &amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now prepare the VM. Beware, this will rapidly fill-in your /nix/store
with big images. (&lt;code&gt;nix-store --delete /nix/store/*libvirtd-image*&lt;/code&gt; to
clean them selectively if you’re doing tests)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# This command will fail due to missing images&lt;/span&gt;
nixops&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;--create-only
&lt;span class="c1"&gt;# Find the path to images at the beginning of the output. It will be&lt;/span&gt;
&lt;span class="c1"&gt;# slightly different from what you would get with nix-build due to&lt;/span&gt;
&lt;span class="c1"&gt;# some parameters given by nixops&lt;/span&gt;
&lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-libvirtd-image

&lt;span class="c1"&gt;# Stop VM.&lt;/span&gt;
virsh&lt;span class="w"&gt; &lt;/span&gt;destroy&lt;span class="w"&gt; &lt;/span&gt;nixops-...-testzfs

&lt;span class="c1"&gt;# Copy additional disks to places written in libvirtd.nix&lt;/span&gt;
&lt;span class="c1"&gt;# For some reason, sometimes I had to replace the first disk too in&lt;/span&gt;
&lt;span class="c1"&gt;# libvirtd folder.&lt;/span&gt;
cp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$P&lt;/span&gt;/disk2.qcow2&lt;span class="w"&gt; &lt;/span&gt;/path/to/disk2.qcow2
cp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$P&lt;/span&gt;/disk3.qcow2&lt;span class="w"&gt; &lt;/span&gt;/path/to/disk3.qcow2
chmod&lt;span class="w"&gt; &lt;/span&gt;gu+w&lt;span class="w"&gt; &lt;/span&gt;/path/to/disk2.qcow2&lt;span class="w"&gt; &lt;/span&gt;/path/to/disk3.qcow2

&lt;span class="c1"&gt;# Same action done by nixops on the first disk&lt;/span&gt;
qemu-img&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;qcow2&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/path/to/disk2.qcow2
qemu-img&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;qcow2&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/path/to/disk3.qcow2

&lt;span class="c1"&gt;# Edit libvirtd and add console configuration (in the &amp;lt;devices&amp;gt; section)&lt;/span&gt;
virsh&lt;span class="w"&gt; &lt;/span&gt;edit&lt;span class="w"&gt; &lt;/span&gt;nixops-...-testzfs
&lt;span class="c1"&gt;# &amp;lt;serial type=&amp;#39;pty&amp;#39;&amp;gt;&amp;lt;target port=&amp;#39;0&amp;#39;/&amp;gt;&amp;lt;/serial&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;# &amp;lt;console type=&amp;#39;pty&amp;#39;&amp;gt;&amp;lt;target type=&amp;#39;serial&amp;#39; port=&amp;#39;0&amp;#39;/&amp;gt;&amp;lt;/console&amp;gt;&lt;/span&gt;

nixops&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;--force-reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you should have a running VM containing two drives in a RAID1 array
plus one unused drive, that mimics your production server, and that I
used as a base for the migration process below.&lt;/p&gt;
&lt;p&gt;In case of problem, you should be able to use &lt;code&gt;virsh console&lt;/code&gt; to get an
actual console of what’s happening on your VM (as early as grub stage).
Also think of doing snapshots if you want to repeat some steps.&lt;/p&gt;
&lt;h2&gt;Migration process&lt;/h2&gt;
&lt;h3&gt;Add the new disk to the RAID array&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Copy partitionning without boot partition&lt;/span&gt;
sfdisk&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;^sector-size:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/21686148-6449-6E6F-744E-656564454649/0657FD6D-A4AB-43C4-84E5-0933C84B4F4F/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sfdisk&lt;span class="w"&gt; &lt;/span&gt;/dev/sdc

&lt;span class="c1"&gt;# Add the new partition to RAID array&lt;/span&gt;
mdadm&lt;span class="w"&gt; &lt;/span&gt;--grow&lt;span class="w"&gt; &lt;/span&gt;/dev/md0&lt;span class="w"&gt; &lt;/span&gt;--level&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--raid-devices&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--add&lt;span class="w"&gt; &lt;/span&gt;/dev/sdc3

&lt;span class="c1"&gt;# Wait for synchronisation to finish&lt;/span&gt;
cat&lt;span class="w"&gt; &lt;/span&gt;/proc/mdstat
&lt;span class="o"&gt;(&lt;/span&gt;...&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Remove sda from the array&lt;/h3&gt;
&lt;p&gt;Beware in this step, depending on your grub configuration it could very
well end up using sda for the next boot if you don’t wipe it correctly
(last command of the step)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mdadm&lt;span class="w"&gt; &lt;/span&gt;/dev/md0&lt;span class="w"&gt; &lt;/span&gt;--fail&lt;span class="w"&gt; &lt;/span&gt;/dev/sda3&lt;span class="w"&gt; &lt;/span&gt;--remove&lt;span class="w"&gt; &lt;/span&gt;/dev/sda3
mdadm&lt;span class="w"&gt; &lt;/span&gt;--grow&lt;span class="w"&gt; &lt;/span&gt;/dev/md0&lt;span class="w"&gt; &lt;/span&gt;--raid-devices&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;

&lt;span class="c1"&gt;# delete old partition (so that grub doesn’t find it by error)&lt;/span&gt;
wipefs&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;/dev/sda3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Add ZFS-specific configuration to nix&lt;/h3&gt;
&lt;p&gt;Add this to nix configuration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;boot&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;supportedFilesystems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zfs&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
networking&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;hostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;9e16a79b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Maintenance target for later&lt;/span&gt;
systemd&lt;span class="o"&gt;.&lt;/span&gt;targets&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;maintenance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Maintenance target with only sshd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="ss"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;network-online.target&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;network-setup.service&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;sshd.service&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="ss"&gt;requires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;network-online.target&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;network-setup.service&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;sshd.service&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="ss"&gt;unitConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;AllowIsolate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;yes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And deploy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nixops&lt;span class="w"&gt; &lt;/span&gt;deploy
&lt;span class="c1"&gt;# nixos-rebuild switch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Convert sda3 to a ZFS filesystem&lt;/h3&gt;
&lt;p&gt;I wanted to use this migration to encrypt my filesystem at the same
time. But doing it correctly requires specific configuration (in
initrd) which I didn’t want to risk doing concurrently with the
migration. So for now the password will be in cleartext (I’m aware
it makes the encryption useless, but since encryption cannot be
switched on later I need to activate it now. If someone obtains root
access to your system during that time your encryption is screwed -
he can obtain the ZFS master encryption key -, otherwise it can just
be activated with a proper process later)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Repartition your disk, it’s not recommended to have /boot in ZFS for now&lt;/span&gt;
&lt;span class="c1"&gt;# remove sda3, create a 2GB partition for /boot and create a new root partition&lt;/span&gt;
sfdisk&lt;span class="w"&gt; &lt;/span&gt;--delete&lt;span class="w"&gt; &lt;/span&gt;/dev/sda&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
fdisk&lt;span class="w"&gt; &lt;/span&gt;/dev/sda
mdadm&lt;span class="w"&gt; &lt;/span&gt;--create&lt;span class="w"&gt; &lt;/span&gt;/dev/md1&lt;span class="w"&gt; &lt;/span&gt;--metadata&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.90&lt;span class="w"&gt; &lt;/span&gt;--level&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--force&lt;span class="w"&gt; &lt;/span&gt;--raid-devices&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/sda3
mkfs.ext4&lt;span class="w"&gt; &lt;/span&gt;/dev/md1
mkdir&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/md1&lt;span class="w"&gt; &lt;/span&gt;/mnt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;12345678&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/mnt/pass.key&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;go-rwx&lt;span class="w"&gt; &lt;/span&gt;/mnt/pass.key
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;12345678&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/boot/pass.key&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;go-rwx&lt;span class="w"&gt; &lt;/span&gt;/boot/pass.key
zpool&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;xattr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sa&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;acltype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;posixacl&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;atime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;off&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ashift&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;mountpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;legacy&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;zpool&lt;span class="w"&gt; &lt;/span&gt;sda4
zfs&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;encryption&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;keyformat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;passphrase&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;keylocation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file:///boot/pass.key&lt;span class="w"&gt; &lt;/span&gt;zpool/root
zfs&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;zpool/root/nix
zfs&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;atime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;zpool/root/var
zfs&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;disabled&lt;span class="w"&gt; &lt;/span&gt;zpool/root/tmp
zfs&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;zpool/root/etc
umount&lt;span class="w"&gt; &lt;/span&gt;/mnt
mount&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;zfs&lt;span class="w"&gt; &lt;/span&gt;zpool/root&lt;span class="w"&gt; &lt;/span&gt;/mnt
mkdir&lt;span class="w"&gt; &lt;/span&gt;/mnt/nix&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;zfs&lt;span class="w"&gt; &lt;/span&gt;zpool/root/nix&lt;span class="w"&gt; &lt;/span&gt;/mnt/nix
mkdir&lt;span class="w"&gt; &lt;/span&gt;/mnt/var&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;zfs&lt;span class="w"&gt; &lt;/span&gt;zpool/root/var&lt;span class="w"&gt; &lt;/span&gt;/mnt/var
mkdir&lt;span class="w"&gt; &lt;/span&gt;/mnt/tmp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;zfs&lt;span class="w"&gt; &lt;/span&gt;zpool/root/tmp&lt;span class="w"&gt; &lt;/span&gt;/mnt/tmp
mkdir&lt;span class="w"&gt; &lt;/span&gt;/mnt/etc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;zfs&lt;span class="w"&gt; &lt;/span&gt;zpool/root/etc&lt;span class="w"&gt; &lt;/span&gt;/mnt/etc
mkdir&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;/dev/md1&lt;span class="w"&gt; &lt;/span&gt;/mnt/boot
rsync&lt;span class="w"&gt; &lt;/span&gt;-aHAXS&lt;span class="w"&gt; &lt;/span&gt;--one-file-system&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;/mnt/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Let NixOS know about new filesystem&lt;/h3&gt;
&lt;p&gt;Until there, you could do everything while keeping your system
running, rebooting etc. From now on, everything must be done in one
go (no reboot inbetween) or you might not be able to properly boot&lt;/p&gt;
&lt;p&gt;Obtain your /boot uuid and replace below:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;fsType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zfs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zpool/root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/boot&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;fsType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ext4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/dev/disk/by-uuid/5b27af91-f515-44f4-9a65-1516326d9297&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/etc&amp;quot;&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;fsType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zfs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zpool/root/etc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/nix&amp;quot;&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;fsType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zfs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zpool/root/nix&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/tmp&amp;quot;&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;fsType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zfs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zpool/root/tmp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
fileSystems&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var&amp;quot;&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;fsType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zfs&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="ss"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;zpool/root/var&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
boot&lt;span class="o"&gt;.&lt;/span&gt;initrd&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;&amp;quot;/boot/pass.key&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/boot/pass.key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Deploy partially:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nixops&lt;span class="w"&gt; &lt;/span&gt;deploy&lt;span class="w"&gt; &lt;/span&gt;--dry-activate
&lt;span class="c1"&gt;# nixos-rebuild dry-activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Go in maintenance mode, resynchronize and prepare next boot&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;isolate&lt;span class="w"&gt; &lt;/span&gt;maintenance.target
systemctl&lt;span class="w"&gt; &lt;/span&gt;stop&lt;span class="w"&gt; &lt;/span&gt;systemd-journald&lt;span class="w"&gt; &lt;/span&gt;systemd-journald.socket&lt;span class="w"&gt; &lt;/span&gt;systemd-journald-dev-log.socket&lt;span class="w"&gt; &lt;/span&gt;systemd-journald-audit.socket
rsync&lt;span class="w"&gt; &lt;/span&gt;-aHAXS&lt;span class="w"&gt; &lt;/span&gt;--delete&lt;span class="w"&gt; &lt;/span&gt;--one-file-system&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;/mnt/

&lt;span class="c1"&gt;# Prepare next boot in zfs filesystem&lt;/span&gt;
&lt;span class="nv"&gt;NIXOS_INSTALL_BOOTLOADER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;nixos-enter&lt;span class="w"&gt; &lt;/span&gt;--root&lt;span class="w"&gt; &lt;/span&gt;/mnt/&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;/nix/var/nix/profiles/system/bin/switch-to-configuration&lt;span class="w"&gt; &lt;/span&gt;boot
&lt;span class="c1"&gt;# Prepare next boot in raid array - for grub&lt;/span&gt;
/nix/var/nix/profiles/system/bin/switch-to-configuration&lt;span class="w"&gt; &lt;/span&gt;boot

&lt;span class="c1"&gt;# Unmount everything and prepare the filesystem&lt;/span&gt;
umount&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;/mnt

&lt;span class="c1"&gt;# Remove sdb3 from raid array and attach it to ZFS. We still have&lt;/span&gt;
&lt;span class="c1"&gt;# the data both in raid and zfs, and no file is modified due to&lt;/span&gt;
&lt;span class="c1"&gt;# maintenance mode so they’re synchronized&lt;/span&gt;
mdadm&lt;span class="w"&gt; &lt;/span&gt;/dev/md0&lt;span class="w"&gt; &lt;/span&gt;--fail&lt;span class="w"&gt; &lt;/span&gt;/dev/sdb3&lt;span class="w"&gt; &lt;/span&gt;--remove&lt;span class="w"&gt; &lt;/span&gt;/dev/sdb3

&lt;span class="c1"&gt;# Repartition /dev/sdb similarly to /dev/sda&lt;/span&gt;
fdisk&lt;span class="w"&gt; &lt;/span&gt;/dev/sdb
&lt;span class="c1"&gt;# Add sdb3 to the /boot array&lt;/span&gt;
mdadm&lt;span class="w"&gt; &lt;/span&gt;--grow&lt;span class="w"&gt; &lt;/span&gt;/dev/md1&lt;span class="w"&gt; &lt;/span&gt;--level&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--raid-devices&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--add&lt;span class="w"&gt; &lt;/span&gt;/dev/sdb3
zpool&lt;span class="w"&gt; &lt;/span&gt;attach&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;zpool&lt;span class="w"&gt; &lt;/span&gt;sda4&lt;span class="w"&gt; &lt;/span&gt;sdb4

&lt;span class="c1"&gt;# Wait until it’s fully synchronized (or feel lucky and don’t wait)&lt;/span&gt;
zpool&lt;span class="w"&gt; &lt;/span&gt;status

&lt;span class="c1"&gt;# Restart&lt;/span&gt;
shutdown&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;now
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Cleanup old system&lt;/h3&gt;
&lt;p&gt;Now that the installation is finished, you may cleanup the
additional disk and profit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mdadm&lt;span class="w"&gt; &lt;/span&gt;--stop&lt;span class="w"&gt; &lt;/span&gt;/dev/md0
wipefs&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;/dev/sdc3
shred&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;/dev/sdc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="informatique"></category><category term="raid"></category><category term="ZFS"></category><category term="NixOS"></category></entry><entry><title>Manage your session with systemd</title><link href="https://www.immae.eu/blog/2014/05/26/manage-your-session-with-systemd/" rel="alternate"></link><published>2014-05-26T23:00:00+02:00</published><updated>2014-05-26T23:00:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-05-26:/blog/2014/05/26/manage-your-session-with-systemd/</id><summary type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A lot of distribution are making their way to "systemd" as an alternative to
System V.&lt;/p&gt;

&lt;p&gt;One of the advantages of systemd is that it offers a service management for
users, and it is this system that I plan to present here to handle our session.
Systemd is still …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;A lot of distribution are making their way to "systemd" as an alternative to
System V.&lt;/p&gt;

&lt;p&gt;One of the advantages of systemd is that it offers a service management for
users, and it is this system that I plan to present here to handle our session.
Systemd is still under active development, including the user part. This guide
reflects the big change that happened in version 206 of systemd on which most
current tutorial are based. This setup has been tested on version 212.&lt;/p&gt;
&lt;!--
----
--&gt;

&lt;p&gt;When a user session starts (either remotely via ssh or local), an instance of
&lt;code&gt;systemd --user&lt;/code&gt; starts for that user. This instance has the role to
start user services, in a similar way to process 1 but dedicated to the user. 
Note that by default these services disappear with the user session&lt;/p&gt;

&lt;h2&gt;Starting &lt;code&gt;systemd --user&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Before version 206 (as far as I can tell), it was the user's responsibility
to start (or not) this instance. Now she cannot anymore be started by the user
and it must be run by root.&lt;/p&gt;

&lt;p&gt;It is started automatically at login provided that the
&lt;code&gt;pam_systemd&lt;/code&gt; module is active in &lt;code&gt;pam&lt;/code&gt; for the requested
session. For that, we add a line of the form&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-session&lt;span class="w"&gt;   &lt;/span&gt;optional&lt;span class="w"&gt;   &lt;/span&gt;pam_systemd.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The "-" indicates that it is not essential to the session. In other words: if it
fails to start we don't care). With Archlinux, the file
&lt;code&gt;/etc/pam.d/system-login&lt;/code&gt; already contains this line and concerns any
kind of connection (local and remote).&lt;/p&gt;

&lt;h2&gt;Systemd arrangement&lt;/h2&gt;
&lt;p&gt;Systemd separates the services and session between slice/scope/service,
making heavy use of the &lt;a
href="http://fr.wikipedia.org/wiki/Cgroups"&gt;cgroups&lt;/a&gt; feature (it is a way to
group a collection of processes and their possible children without possible &lt;q
class="quoteme"&gt;escape&lt;/q&gt;). A typical system running systemd then looks like
that (you can obtain it with &lt;code&gt;systemd-cgls&lt;/code&gt;):
&lt;ul&gt;
&lt;li&gt;system.slice
        &lt;ul&gt;
        &lt;li&gt;service_system1.service&lt;/li&gt;
        &lt;li&gt;service_system2.service&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;user.slice
        &lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;Program 1&lt;/li&gt;
                        &lt;li&gt;Program 2&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;session-c2.scope&lt;/li&gt;
                &lt;li&gt;session-c3.scope&lt;/li&gt;
                &lt;li&gt;user@1000.service
                        &lt;ul&gt;
                        &lt;li&gt;systemd --user&lt;/li&gt;
                        &lt;li&gt;service_user1000_1.service&lt;/li&gt;
                        &lt;li&gt;service_user1000_2.service&lt;/li&gt;
                        &lt;li&gt;service_user1000_3.service&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;li&gt;user-1001.slice
                &lt;ul&gt;
                &lt;li&gt;session-c4.scope
                        &lt;ul&gt;
                        &lt;li&gt;Program 1&lt;/li&gt;
                        &lt;li&gt;Program 2&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;session-c5.scope&lt;/li&gt;
                &lt;li&gt;session-c6.scope&lt;/li&gt;
                &lt;li&gt;user@1001.service
                        &lt;ul&gt;
                        &lt;li&gt;systemd --user&lt;/li&gt;
                        &lt;li&gt;service_user1001_1.service&lt;/li&gt;
                        &lt;li&gt;service_user1001_2.service&lt;/li&gt;
                        &lt;li&gt;service_user1001_3.service&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
Note that the services of the user ar started in a context separate to the
session itself. This has to be remembered, for instance for environment
variables scopes.&lt;/p&gt;

&lt;p&gt;As soon as all the &lt;code&gt;session-c*.scope&lt;/code&gt; of a user are exited, the
corresponding &lt;code&gt;user@.service&lt;/code&gt; will also be stopped, including all the
sub-services. This is a point to remember! For instance, by default, using
"timer" unit files of systemd as a replacement for cron won't work for the user
if he's not there!&lt;br /&gt;
We'll see later how to deal with that.&lt;/p&gt;
&lt;h2&gt;User services&lt;/h2&gt;
&lt;h3&gt;Comparison&lt;/h3&gt;
&lt;p&gt;User services are handled in exactly the same way as system services, except
that the units are sought in different folders (see &lt;code&gt;man
systemd.unit&lt;/code&gt;). When &lt;code&gt;systemd --user&lt;/code&gt; starts, unit
&lt;code&gt;default.target&lt;/code&gt; is started and has the role to start other necessary
services.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;systemctl --user&lt;/code&gt; and &lt;code&gt;dbus&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Services managed by systemd (whether system or user) are managed primarily
through the command &lt;code&gt;systemctl&lt;/code&gt; (&lt;code&gt;--user&lt;/code&gt;), which strongly
depends on a correct dbus installation. First thing to do is thus to ensure that
the &lt;code&gt;dbus&lt;/code&gt; daemon runs, both at system level (&lt;q
class="quoteme"&gt;system bus&lt;/q&gt;) and user level (&lt;q class="quoteme"&gt;session
bus&lt;/q&gt;). For the system part, we simply need to add a dependency to
&lt;code&gt;user@.service&lt;/code&gt;. We will also normalize the path to the &lt;q
class="quoteme"&gt;session bus&lt;/q&gt; socket by giving the appropriate environment
variable &lt;code&gt;DBUS_SESSION_BUS_ADDRESS&lt;/code&gt;. Since user@.service is a parent
of all user services, we can use it to transmit the variable&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/systemd/system/user@.service.d/dbus_env.conf&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nv"&gt;Wants&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dbus.service
&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DBUS_SESSION_BUS_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;unix:path&lt;span class="o"&gt;=&lt;/span&gt;/run/user/%I/bus
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;Line 2 of the file indicates that we require that the system
&lt;code&gt;dbus&lt;/code&gt; is started, while line 5 concerns the environment variable for
the user's session bus. Don't confuse these services, they correspond to two
different &lt;q class="quoteme"&gt;buses&lt;/q&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;In the sequence, we will define the different services that we will need.
They can be defined or activated globally or by user's choice. This depends both
on the location of the unit file (&lt;code&gt;/etc/systemd/user/&lt;/code&gt; vs
&lt;code&gt;$HOME/.config/systemd/user&lt;/code&gt;) and on the way it is activated (with
&lt;code&gt;--global&lt;/code&gt; vs &lt;code&gt;--user&lt;/code&gt;). Here I will define the services
and sockets associated to the session dbus globally, but I will let the user
chose whether he turns them on or note
l'utilisateur&amp;nbsp;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/systemd/user/dbus.service&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;D-Bus&lt;span class="w"&gt; &lt;/span&gt;Message&lt;span class="w"&gt; &lt;/span&gt;Bus
&lt;span class="nv"&gt;Requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dbus.socket

&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/dbus-daemon&lt;span class="w"&gt; &lt;/span&gt;--session&lt;span class="w"&gt; &lt;/span&gt;--address&lt;span class="o"&gt;=&lt;/span&gt;systemd:&lt;span class="w"&gt; &lt;/span&gt;--nofork&lt;span class="w"&gt; &lt;/span&gt;--nopidfile&lt;span class="w"&gt; &lt;/span&gt;--systemd-activation
&lt;span class="nv"&gt;ExecReload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/dbus-send&lt;span class="w"&gt; &lt;/span&gt;--print-reply&lt;span class="w"&gt; &lt;/span&gt;--session&lt;span class="w"&gt; &lt;/span&gt;--type&lt;span class="o"&gt;=&lt;/span&gt;method_call&lt;span class="w"&gt; &lt;/span&gt;--dest&lt;span class="o"&gt;=&lt;/span&gt;org.freedesktop.DBus&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;org.freedesktop.DBus.ReloadConfig
&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always
&lt;span class="nv"&gt;RestartSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Note that the main difference between this unit and the corresponding system
unit resides in the use of &lt;code&gt;--session&lt;/code&gt; instead of &lt;code&gt;--system&lt;/code&gt;)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/systemd/user/dbus.socket&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;D-Bus&lt;span class="w"&gt; &lt;/span&gt;Message&lt;span class="w"&gt; &lt;/span&gt;Bus&lt;span class="w"&gt; &lt;/span&gt;Socket
&lt;span class="nv"&gt;Before&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sockets.target

&lt;span class="o"&gt;[&lt;/span&gt;Socket&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;ListenStream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/run/user/%U/bus

&lt;span class="o"&gt;[&lt;/span&gt;Install&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default.target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(&lt;code&gt;default.target&lt;/code&gt; is the default activated target by systemd).&lt;p/&gt;


&lt;p&gt;From now on, the hardest part is done. We will create a unit 
&lt;code&gt;my_services.target&lt;/code&gt; alias of &lt;code&gt;default.target&lt;/code&gt;&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/my_services.target
    [Unit]
    Description=My services
    Wants=dbus.service
    AllowIsolate=true

    [Install]
    Alias=default.target

&lt;p&gt;and then we create unit files in the same folder. Then, we activate them using
the well know command &lt;code&gt;systemctl&lt;/code&gt;, but with an argument
&lt;code&gt;--user&lt;/code&gt;. The rest of the article consists essentially in tricks and
interesting specific cases.&lt;/p&gt;

&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Important notice&lt;/p&gt;
&lt;p class="c_important"&gt;The directive &lt;code&gt;After&lt;/code&gt; doesn't have the same
effect for a &lt;q class="quoteme"&gt;service&lt;/q&gt; unit and a &lt;q
class="quoteme"&gt;target&lt;/q&gt; unit. A service will be started only once all the
unit quoted in &lt;code&gt;After&lt;/code&gt; are ready (for the definition of &lt;q
class="quoteme"&gt;ready&lt;/q&gt;, see &lt;code&gt;man systemd.service&lt;/code&gt;, bloc
&lt;code&gt;Type=&lt;/code&gt;), while for a target it is assumed that the services are
&lt;em&gt;part of it&lt;/em&gt; (and can then be started concurrently to other
services).&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;User services that last&lt;/h2&gt;
&lt;p&gt;By default, services associated to an user (everything that is below
&lt;code&gt;user@1001.service&lt;/code&gt; in the tree above) are stopped when the user
disconnects. This includes timers, that we would like to use as a replacement
for crontab.&lt;/p&gt;

&lt;p&gt;We can bypass that with this command:&lt;/p&gt;

    :::bash
    loginctl enable-linger user

&lt;p&gt;In that case, &lt;code&gt;user@.service&lt;/code&gt; will be started as soon as boot for the
corresponding user, even when he is not there.&lt;/p&gt;

&lt;p&gt;I won't go any further into details on how to define the equivelnt of
crontabs for systemd, this kind of feature is already well explained in manual
pages as well as systemd-dedicated websites (see &lt;code&gt;man
systemd.timer&lt;/code&gt;). The trick given here deals with the issue of having
crontabs equivalent that last for an user even when he's not there.&lt;/p&gt;

&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Important notice&lt;/p&gt;
&lt;p class="c_important"&gt;Usually crontabs send emails when there is output. As far
as I know there is no such feature in systemd services and everything is logged
in the journal.&lt;/p&gt;&lt;/div&gt;

&lt;h2 id="article_variables"&gt;Environment variables&lt;/h2&gt;
&lt;p&gt;Environment variables can become a true headache when we use services. For
instance, how can we transmit variables necessary to the services like
GPG_AGENT_INFO or SSH_AUTH_SOCK or even DISPLAY. One way to do it is to specify
in the unit file a directive of the form&lt;/p&gt;

    :::bash
    Environment=DISPLAY=:0

or

    :::bash
    EnvironmentFile=/file/to/load

&lt;p&gt;The problem is that this configuration is static, and must be defined for each
service separately or globally in a file like
&lt;code&gt;/etc/systemd/system/user@.service.d/environment.conf&lt;/code&gt;. We also lose
the usual &lt;q class="quoteme"&gt;dynamism&lt;/q&gt; of configuration scripts.&lt;/p&gt;

&lt;p&gt;Here, we will make use of the command &lt;code&gt;systemctl --user
import-environment&lt;/code&gt; to solve our problem. This command permits to import
environment variables that will be included in any &lt;em&gt;subsequent&lt;/em&gt; service.
We start by creating a service setenv.service that will start a script loading
the environment. As far as I am concerned, I have to different environment
depending on whether I am in command line or graphical. My service file then
looks like that:&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/setenv@.service
    [Unit]
    Description=Set environment
    Wants=dbus.service gpg-agent.service ssh-agent.service
    After=dbus.service gpg-agent.service ssh-agent.service

    [Service]
    Type=oneshot
    Environment=SSH_AUTH_SOCK=%t/ssh_auth_sock
    ExecStart=%h/bin/systemd_setenv %i

&lt;p&gt;And then I activate services &lt;code&gt;setenv@type.service&lt;/code&gt; depending on my
needs. Here I also defined an environment variable inside the unit. The only
reason for that is that the part "%t" (/run/user/1000/) is easier to find in a
unit file...&lt;/p&gt;

&lt;p&gt;Here is an example script to define my environment:&lt;/p&gt;

    :::bash
    # $HOME/bin/systemd_setenv
    #!/bin/zsh

    if [ "x$1" = "xcommon" ]; then
            . /etc/zsh/zprofile
            source $HOME/.gpg-agent-info
            export GPG_AGENT_INFO
            systemctl --user import-environment
            systemctl --user unset-environment PWD OLDPWD SHLVL _ MANAGERPID
    elif [ "x$1" = "xgraphical" ]; then
            export XDG_CONFIG_HOME="$HOME/.config/"
            export SAL_USE_VCLPLUGIN=gtk
            export XDG_MENU_PREFIX="lxde-"
            export DISPLAY=:0
            systemctl --user import-environment XDG_CONFIG_HOME SAL_USE_VCLPLUGIN XDG_MENU_PREFIX DISPLAY
    fi

As I mentionned before, I have two different environments depending on whether I
started a graphical session or simply a command line connection. Note that even
if I leave the graphical environment, the variables are still there! We could
make use of the command

    :::bash
    systemctl --user unset-environment VARIABLE1 VARIABLE2

&lt;p&gt;in the same way to destroy variables after use (in which case the setenv service
has to be adapted).&lt;/p&gt;

&lt;h2&gt;The &lt;code&gt;*-agent&lt;/code&gt;s&lt;/h2&gt;
&lt;p&gt;Services that are worth starting no matter if we are in a graphical or
command line remote session are &lt;code&gt;ssh-agent&lt;/code&gt; and
&lt;code&gt;gpg-agent&lt;/code&gt;. However we need to think to transmit environment
variables to the process that are interested (see &lt;a
href="#article_variables"&gt;Above section&lt;/a&gt; for more information).&lt;/p&gt;

&lt;p&gt;The service &lt;a href="https://github.com/vodik/envoy"&gt;envoy&lt;/a&gt; should also be
considered to manage these agents. I prefer to separate both agent, which is not
possible with envoy.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;ssh-agent&lt;/code&gt;, we can directly indicate in the command where we
want to put the socket, which makes things easier:&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/ssh-agent.service
    [Unit]
    Description=ssh-agent
    ConditionFileIsExecutable=/usr/bin/ssh-agent

    [Service]
    ExecStart=/usr/bin/ssh-agent -d -a %t/ssh_auth_sock
    Restart=always

    [Install]
    WantedBy=my_services.target

&lt;p&gt;For &lt;code&gt;gpg-agent&lt;/code&gt;, we can only tell him to save the informations in
a file: the socket won't end in a predictable path.&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/gpg-agent.service
    [Unit]
    Description=gpg-agent
    ConditionFileIsExecutable=/usr/bin/gpg-agent

    [Service]
    ExecStart=/usr/bin/gpg-agent --daemon --write-env-file %h/.gpg-agent-info
    Type=forking
    Restart=always

    [Install]
    WantedBy=my_services.target

We can then source the file &lt;code&gt;$HOME/.gpg-agent-info&lt;/code&gt; to access the
agent socket.

    :::bash
    source $HOME/.gpg-agent-info

&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;The fact that we don't have a standard place can be a problem
if the agent is restarted: most probably, the socket won't be in the same place,
and programs that already started won't be able to contact the agent.&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Using systemd to manage your graphical session&lt;/h2&gt;
&lt;p&gt;It can be tempting to use systemd to manage also your graphical session:
defining your window manager as a service and be able to switch to another
window manager at will without being obliged to restart your session.
This can lead to some problems as we will see later.&lt;/p&gt;

&lt;h3&gt;Graphical session as a service file&lt;/h3&gt;
&lt;p&gt;The simplest to do there is to define a unit file  
&lt;code&gt;graphical.target&lt;/code&gt; (or &lt;code&gt;graphical@.target&lt;/code&gt; if you want to
define several window managers) and activate it in the &lt;code&gt;.xsession&lt;/code&gt;
script (or whichever is executed when your session starts).&lt;br /&gt;
It can be necessary to correctly define the environment variables at that time,
in which case each uni will need the service
&lt;code&gt;setenv@graphical.service&lt;/code&gt; activated as a prerequisite (as indicated
before, it it not sufficient to put it int the &lt;code&gt;After&lt;/code&gt; directive in
graphical.target).&lt;/p&gt;
&lt;p&gt;As pointed initialy, it is tempting to define your graphical session as a
service. However:&lt;br /&gt;
First, the command systemct returns immediatly. Thus, a &lt;code&gt;.xsession&lt;/code&gt;
file containing only something like that:&lt;/p&gt;

    :::bash
    # $HOME/.xsession
    export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
    systemctl --user start graphical.target

&lt;p&gt;won't be enough, because your graphical session will disappear as soon as it
starts (NB: the &lt;code&gt;export DBUS_SESSION_BUS_ADDRESS&lt;/code&gt; is necessary to
permit dialog with &lt;code&gt;systemd&lt;/code&gt;). There exists programs such as
&lt;a href="https://github.com/Stebalien/systemd-wait"&gt;systemd-wait&lt;/a&gt; that do
exactly what we want to: wait for a service to end.&lt;br /&gt;&lt;br /&gt;
The second problem can be more annoying, and comes from the difference between
the user session and services. If we don't take care, we will end up with
something like that:
&lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;systemd-wait -q --user graphique.service failed inactive&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;user@1000.service
                        &lt;ul&gt;
                        &lt;li&gt;systemd --user&lt;/li&gt;
                        &lt;li&gt;graphique.service
                                &lt;ul&gt;
                                &lt;li&gt;openbox&lt;/li&gt;
                                &lt;li&gt;firefox&lt;/li&gt;
                                &lt;li&gt;xterm&lt;/li&gt;
                                &lt;li&gt;xterm&lt;/li&gt;
                                &lt;/ul&gt;
                        &lt;/li&gt;
                        &lt;li&gt;service_2.service&lt;/li&gt;
                        &lt;li&gt;service_3.service&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
How can this be a problem? Because the only process considered &lt;q
class="quoteme"&gt;active&lt;/q&gt; there is &lt;code&gt;systemd-wait&lt;/code&gt; as we put it in
the &lt;code&gt;.xsession&lt;/code&gt; file. This can have consequences for instance in
right management, see &lt;a href="#polkit"&gt;next section about polkit&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Note about &lt;code&gt;slim&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;As specified on Archlinux website, &lt;code&gt;slim&lt;/code&gt; is not compatible with
&lt;code&gt;systemd --user&lt;/code&gt; (at least it wasn't at the time when this article
was writtent). What does that mean, and what can we do about it?&lt;/p&gt;
&lt;p&gt;First of all, let's have a closer look to how &lt;code&gt;slim&lt;/code&gt; works.
&lt;code&gt;slim&lt;/code&gt; is a connexion manager, that is, a sort of replacement of
login in terminal-like tty's, but with a graphical interface. This has several
implications: it has to deal with the problem of starting an X server, and has 
to launch the user session after his connexion. But he also have to take back
control once the user leaves.&lt;/p&gt;
&lt;p&gt;As the user logs in, slim start (via pam configuration) an instance of
&lt;code&gt;systemd --user&lt;/code&gt;, as well as a &lt;q class="quoteme"&gt;session script&lt;/q&gt;
(for instance the .xsession file). It does not have to start an X server, since
it is already there.&lt;br /&gt;
However when the user logs out however, it doesn't restart everything and reuses
the state in which it was before. In the point of view of systemd, it then ends
in the "scope" of the preceding user (even if it is still a root process):&lt;/p&gt;
&lt;div style="float:left"&gt;
&lt;p&gt;Before log out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;system.slice
        &lt;ul&gt;
        &lt;li&gt;slimd.service
                &lt;ul&gt;
                &lt;li&gt;slim&lt;/li&gt;
                &lt;li&gt;X&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;user.slice
        &lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;...&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;user@1000.service&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div style="float:left"&gt;
&lt;p&gt;After log out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;system.slice
        &lt;ul&gt;
        &lt;li&gt;slimd.service&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;user.slice
        &lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;slim&lt;/li&gt;
                        &lt;li&gt;X&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;user@1000.service&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr class="clear" /&gt;
&lt;p&gt;This particular behaviour is particularly annoying for the next users. In
Archlinux, slim has been patched recently to avoid this (since &lt;code&gt;slim
1.3.6-4&lt;/code&gt;, 2014-04-21), by forcing slim to quit when a session ends
(argument &lt;code&gt;-nodaemon&lt;/code&gt;), and adding a &lt;code&gt;Restart&lt;/code&gt; directive
to the systemd unit file.&lt;/p&gt;
&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;The &lt;code&gt;Restart&lt;/code&gt; directive is &lt;q
class="quoteme"&gt;on-failure&lt;/q&gt;, but the patch makes slim quit with an error on
purpose.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Another solution which was the one I used until the patch, if you are not
using Archlinux and don't want to patch slim, is to put a line in
&lt;code&gt;/etc/slim.conf&lt;/code&gt; of the form&lt;/p&gt;

    :::bash
    # /etc/slim.conf
    sessionstop_cmd        systemctl restart slim.service

that will have the effect to restart slim at the end of each session (which
essentially does the same as the patch).&lt;/p&gt;

&lt;h2 id="polkit"&gt;Polkit and administrative rights&lt;/h2&gt;
&lt;p&gt;Systemd distinguishes between two kind of users, that is "active" and
"inactive" users. For instance, if two users are both connected on the same
computer (physically), then only one of them is actually "active" (unless you
have several monitors). It also makes a difference whether the user is "local"
or "remote". This information about a session can be obtained with the
command&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;loginctl&lt;span class="w"&gt; &lt;/span&gt;show-session&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;session&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;"session"&lt;/code&gt; is the id of the session (you can list
session ids with &lt;code&gt;loginctl list-sessions&lt;/code&gt;).&lt;br /&gt;
In particular, and that's where it is important, a service is &lt;em&gt;always&lt;/em&gt;
inactive.&lt;/p&gt;

&lt;p&gt;Polkit is a service that permits to give (temporarily or not) more rights to
a user. For instance if you can turn off the computer without typing sudo or
entering a password, then most probably polkit plays a role here. These rights
are aranged depending on the state of the user, whether he is active or inactive
or "any".&lt;/p&gt;
&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Important&lt;/p&gt;
&lt;p class="c_important"&gt;Polkit and systemd don't share the same &lt;em&gt;active&lt;/em&gt;
notions. For polkit, an active/inactive user is local &lt;em&gt;and&lt;/em&gt; &lt;q
class="quoteme"&gt;active/inactive for systemd&lt;/q&gt;. Any other user is in
&lt;q class="quoteme"&gt;any&lt;/q&gt; (in particular remote users). This rule is hard-coded
in function &lt;code&gt;check_authorization_sync&lt;/code&gt; of file
&lt;code&gt;src/polkitbackend/polkitbackendinteractiveauthority.c&lt;/code&gt; in source
code of polkit: &lt;/p&gt;
&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session_is_local&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session_is_active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;implicit_authorization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;polkit_action_description_get_implicit_active&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action_desc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;implicit_authorization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;polkit_action_description_get_implicit_inactive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action_desc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;implicit_authorization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;polkit_action_description_get_implicit_any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action_desc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I won't go into much more details about polkit here, but we can already see
that an &lt;code&gt;xterm&lt;/code&gt; started as a service, and one started directly (for
instance in your &lt;code&gt;.xsession&lt;/code&gt;) won't have the same right for polkit!
We thus have to be careful about that when we want to use &lt;code&gt;systemd
--user&lt;/code&gt; as a session manager, because it will then be unable to shutdown
the computer without using &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;</content><category term="informatique"></category><category term="systemd"></category><category term="daemons"></category><category term="cron"></category><category term="session"></category></entry><entry><title>Shell invocation</title><link href="https://www.immae.eu/blog/2014/05/11/shell-invocation/" rel="alternate"></link><published>2014-05-11T13:40:00+02:00</published><updated>2014-05-11T13:40:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-05-11:/blog/2014/05/11/shell-invocation/</id><summary type="html">&lt;p&gt;Bash and Zsh shells have very different ways to start, and this can be an
issue when we switch from one to the other and back.&lt;/p&gt;
&lt;p&gt;First, we distinguish two &lt;q class="quoteme"&gt;states&lt;/q&gt; for the shell:
&lt;ul&gt;
&lt;li&gt;Login/non-login shell,&lt;/li&gt;
&lt;li&gt;interactive/non-interactive shell.&lt;/li&gt;
&lt;/ul&gt;
Shells make different actions depending on those two states.&lt;/p&gt;
&lt;!--
----
--&gt;

&lt;h2&gt;Login …&lt;/h2&gt;</summary><content type="html">&lt;p&gt;Bash and Zsh shells have very different ways to start, and this can be an
issue when we switch from one to the other and back.&lt;/p&gt;
&lt;p&gt;First, we distinguish two &lt;q class="quoteme"&gt;states&lt;/q&gt; for the shell:
&lt;ul&gt;
&lt;li&gt;Login/non-login shell,&lt;/li&gt;
&lt;li&gt;interactive/non-interactive shell.&lt;/li&gt;
&lt;/ul&gt;
Shells make different actions depending on those two states.&lt;/p&gt;
&lt;!--
----
--&gt;

&lt;h2&gt;Login shell&lt;/h2&gt;
&lt;p&gt;To indicate to a shell that it is a login shell, the calling process will
simply add a &lt;q&gt;-&lt;/q&gt; in front of his name (thus the shell will be called
&lt;code&gt;-bash&lt;/code&gt; or &lt;code&gt;-zsh&lt;/code&gt;). Some shells (like bash) allow command
line argument to fake login shells.&lt;/p&gt;

&lt;p&gt;In a script, we can tell wether we are a login shell or not in a simple way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Bash:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;login_shell
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zsh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;login&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Interactive shell&lt;/h2&gt;
&lt;p&gt;A shell is interactive if it is invoked without argument (or at least none
that imply a command).&lt;/p&gt;
&lt;p&gt;In a script, we can tell wether we are an interactive shell:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*i*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(It is possible to have an interactive shell with a script, for instance if a
file is sourced).
&lt;/p&gt;

&lt;h2&gt;Zsh behavior when invoked&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;In &lt;em&gt;all&lt;/em&gt; cases, &lt;code&gt;/etc/zshenv&lt;/code&gt; and
&lt;code&gt;~/.zshenv&lt;/code&gt; are sourced (in this order).&lt;/li&gt;

&lt;li&gt;If it is a login shell, &lt;code&gt;/etc/zprofile&lt;/code&gt; and
&lt;code&gt;~/.zprofile&lt;/code&gt; are sourced (in this order)
&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;&lt;code&gt;/etc/zprofile&lt;/code&gt; is chosen at compile-time and can
vary depending on the system (On Archlinux it is
&lt;code&gt;/etc/zsh/zprofile&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;

&lt;li&gt;If we have an interactive shell, &lt;code&gt;/etc/zshrc&lt;/code&gt; and
&lt;code&gt;~/.zshrc&lt;/code&gt; are sourced (in this order).&lt;/li&gt;

&lt;li&gt;Finaly, if it is a login shell (again!), &lt;code&gt;/etc/zlogin&lt;/code&gt;
et &lt;code&gt;~/.zlogin&lt;/code&gt; are sourced (in this order).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Bash behavior when invoked&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If it is a login and interactive shell, &lt;code&gt;/etc/profile&lt;/code&gt; is
sourced, and then the first existing one in &lt;code&gt;~/.bash_profile&lt;/code&gt;,
&lt;code&gt;~/.bash_login&lt;/code&gt;, &lt;code&gt;~/.profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If it is an interactive &lt;em&gt;non-login&lt;/em&gt; shell, &lt;code&gt;~/.bashrc&lt;/code&gt; is
sourced.&lt;/li&gt;
&lt;li&gt;Finaly, if the shell is non-interactive, &lt;code&gt;$BASH_ENV&lt;/code&gt; is sourced
(if available).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Bash behavior when invoked as sh&lt;/h2&gt;
&lt;p&gt;In many distributions, &lt;code&gt;sh&lt;/code&gt; is simply a soft link to
&lt;code&gt;bash&lt;/code&gt;. In that case, bash will behave in a different way when
invoked:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If it is an interactive login shell, &lt;code&gt;/etc/profile&lt;/code&gt; and
&lt;code&gt;~/.profile&lt;/code&gt; are sourced.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;$ENV&lt;/code&gt; is a file, it is also sourced.&lt;/li&gt;
&lt;/ol&gt;</content><category term="informatique"></category><category term="shell"></category><category term="Bash"></category><category term="Zsh"></category></entry><entry><title>Shell invocation</title><link href="https://www.immae.eu/blog/2014/05/10/shell-invocation/" rel="alternate"></link><published>2014-05-10T13:40:00+02:00</published><updated>2014-05-10T13:40:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-05-10:/blog/2014/05/10/shell-invocation/</id><summary type="html">&lt;p&gt;Bash et Zsh (pour ceux que je connais) ont des façons très différentes de
démarrer, ce qui peut créer des soucis lorsqu'on passe de l'un à l'autre.&lt;/p&gt;
&lt;p&gt;Pour commencer, on distingue deux &lt;q class="quoteme"&gt;états&lt;/q&gt; du
shell&amp;nbsp;:
&lt;ul&gt;
&lt;li&gt;Shell de login ou non&lt;/li&gt;
&lt;li&gt;Shell interactif ou non&lt;/li&gt;
&lt;/ul&gt;
et les shells font des actions …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Bash et Zsh (pour ceux que je connais) ont des façons très différentes de
démarrer, ce qui peut créer des soucis lorsqu'on passe de l'un à l'autre.&lt;/p&gt;
&lt;p&gt;Pour commencer, on distingue deux &lt;q class="quoteme"&gt;états&lt;/q&gt; du
shell&amp;nbsp;:
&lt;ul&gt;
&lt;li&gt;Shell de login ou non&lt;/li&gt;
&lt;li&gt;Shell interactif ou non&lt;/li&gt;
&lt;/ul&gt;
et les shells font des actions différentes en fonction de ces deux états.&lt;/p&gt;
&lt;!--
----
--&gt;

&lt;h2&gt;Shell de login&lt;/h2&gt;
&lt;p&gt;Pour indiquer à un shell que c'est un shell de login, le programme qui
l'appelle met simplement un &lt;q&gt;-&lt;/q&gt; devant son nom (ainsi le shell s'appellera
&lt;code&gt;-bash&lt;/code&gt; ou &lt;code&gt;-zsh&lt;/code&gt;). Certains shells (bash) permettent de
donner un argument à la ligne de commande pour faire comme si c'était un shell
de login&lt;/p&gt;

&lt;p&gt;Dans un script, on peut savoir qu'on est dans un login de la façon
suivante&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Bash:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;login_shell
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zsh:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;login&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Shell interactif&lt;/h2&gt;
&lt;p&gt;Un shell interactif est tout simplement un shell invoqué sans argument (du
moins aucun qui n'implique une commande)&lt;/p&gt;
&lt;p&gt;Dans un script, on peut savoir qu'on est en mode interactif de la façon
suivante&amp;nbsp;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*i*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Oui c'est possible d'avoir un shell interactif avec un script, par exemple
lorsqu'un fichier est sourcé)
&lt;/p&gt;

&lt;h2&gt;Comportement de zsh à l'invocation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Dans &lt;em&gt;tous&lt;/em&gt; les cas, &lt;code&gt;/etc/zshenv&lt;/code&gt; et
&lt;code&gt;~/.zshenv&lt;/code&gt; sont sourcés (dans cet ordre).&lt;/li&gt;

&lt;li&gt;Si c'est un shell de login, &lt;code&gt;/etc/zprofile&lt;/code&gt; et
&lt;code&gt;~/.zprofile&lt;/code&gt; sont sourcés (dans cet ordre)
&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;&lt;code&gt;/etc/zprofile&lt;/code&gt; est choisi à la compilation et peut
varier selon les systèmes (Sur Archlinux c'est &lt;code&gt;/etc/zsh/zprofile&lt;/code&gt;
par exemple).&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;

&lt;li&gt;Si le shell est interactif, &lt;code&gt;/etc/zshrc&lt;/code&gt; et &lt;code&gt;~/.zshrc&lt;/code&gt;
sont sourcés (dans cet ordre).&lt;/li&gt;

&lt;li&gt;Enfin, si c'est un shell de login (encore&amp;nbsp;!) &lt;code&gt;/etc/zlogin&lt;/code&gt;
et &lt;code&gt;~/.zlogin&lt;/code&gt; sont sourcés (dans cet ordre toujours).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Comportement de bash à l'invocation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Si c'est un shell de login et interactif, &lt;code&gt;/etc/profile&lt;/code&gt; est
sourcé, puis le premier existant parmi &lt;code&gt;~/.bash_profile&lt;/code&gt;,
&lt;code&gt;~/.bash_login&lt;/code&gt;, &lt;code&gt;~/.profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si c'est un shell interactif &lt;em&gt;non login&lt;/em&gt;, &lt;code&gt;~/.bashrc&lt;/code&gt; est
sourcé.&lt;/li&gt;
&lt;li&gt;Enfin, si c'est un shell non-interactif, &lt;code&gt;$BASH_ENV&lt;/code&gt; est
sourcé.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Bash invoqué comme sh&lt;/h2&gt;
&lt;p&gt;Dans beaucoup de distributions, &lt;code&gt;sh&lt;/code&gt; est simplement un lien
symbolique vers &lt;code&gt;bash&lt;/code&gt;. Dans ce cas, bash se comportera différemment
à l'invocation&amp;nbsp;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Si c'est un shell de login et interactif, &lt;code&gt;/etc/profile&lt;/code&gt; et
&lt;code&gt;~/.profile&lt;/code&gt; sont sourcés&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;$ENV&lt;/code&gt; est un fichier, il est sourcé également&lt;/li&gt;
&lt;/ol&gt;</content><category term="informatique"></category><category term="shell"></category><category term="Bash"></category><category term="Zsh"></category></entry><entry><title>Gérer sa session avec systemd</title><link href="https://www.immae.eu/blog/2014/05/10/gerer-sa-session-avec-systemd/" rel="alternate"></link><published>2014-05-10T00:00:00+02:00</published><updated>2014-05-10T00:00:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-05-10:/blog/2014/05/10/gerer-sa-session-avec-systemd/</id><summary type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;De plus en plus de distributions passent à "systemd" comme alternative à l'init
de System V.&lt;/p&gt;

&lt;p&gt;L'un des avantages de systemd est d'avoir un système de services pour
l'utilisateur, et c'est ce système qu'on va utiliser pour gérer notre session.
systemd est encore en développement actif, notamment pour la …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;De plus en plus de distributions passent à "systemd" comme alternative à l'init
de System V.&lt;/p&gt;

&lt;p&gt;L'un des avantages de systemd est d'avoir un système de services pour
l'utilisateur, et c'est ce système qu'on va utiliser pour gérer notre session.
systemd est encore en développement actif, notamment pour la partie utilisateur.
Ce guide tient compte du grand changement qu'il y a eu suite à la version 206 et
sur laquelle sont basés la plupart des guides existant actuellement, et
fonctionne au moins à la version 212.&lt;/p&gt;
&lt;!--
----
--&gt;

&lt;p&gt;Lorsqu'une session utilisateur démarre (que ce soit à distance via ssh ou en
local), une instance de &lt;code&gt;systemd --user&lt;/code&gt; démarre pour cet
utilisateur. Cette instance a pour but de démarrer des services pour
l'utilisateur, de façon similaire au processus 1 mais pour l'utilisateur. À
noter que par défaut ces services se terminent quand la session de l'utilisateur
disparaît.&lt;/p&gt;

&lt;h2&gt;Démarrage de &lt;code&gt;systemd --user&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Avant la version 206, sauf erreur, c'était l'utilisateur qui pouvait choisir de
démarrer (ou non) cette instance. Maintenant elle ne peut plus être démarrée par
l'utilisateur et c'est le gestionnaire qui doit la lancer.&lt;/p&gt;

&lt;p&gt;Elle est démarrée automatiquement à la connexion à condition que le module
&lt;code&gt;pam_systemd&lt;/code&gt; soit actif dans &lt;code&gt;pam&lt;/code&gt; pour le type de
session demandé. Pour cela, on ajoute une ligne de la forme&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;-session&lt;span class="w"&gt;   &lt;/span&gt;optional&lt;span class="w"&gt;   &lt;/span&gt;pam_systemd.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Le "-" indiquant que ce n'est pas essentiel à la session. Dit autrement&amp;nbsp;:
si ça plante c'est pas grave on continue quand même). Sous Archlinux, le fichier
&lt;code&gt;/etc/pam.d/system-login&lt;/code&gt; contient déjà cette ligne et concerne tous
les types de connexion, locale ou distante.&lt;/p&gt;

&lt;h2&gt;Agencement de systemd&lt;/h2&gt;
&lt;p&gt;Systemd sépare les différents services en slice/scope/service, via l'utilisation
de &lt;a href="http://fr.wikipedia.org/wiki/Cgroups"&gt;cgroups&lt;/a&gt; (une façon de
regrouper un ensemble de processus et leurs éventuels descendants sans &lt;q
class="quoteme"&gt;échappatoire&lt;/q&gt; possible). Un système typique ressemble à
ceci (obtenu avec &lt;code&gt;systemd-cgls&lt;/code&gt;)&amp;nbsp;:
&lt;ul&gt;
&lt;li&gt;system.slice
        &lt;ul&gt;
        &lt;li&gt;service_systeme1.service&lt;/li&gt;
        &lt;li&gt;service_systeme2.service&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;user.slice
        &lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;Programme 1&lt;/li&gt;
                        &lt;li&gt;Programme 2&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;session-c2.scope&lt;/li&gt;
                &lt;li&gt;session-c3.scope&lt;/li&gt;
                &lt;li&gt;user@1000.service
                        &lt;ul&gt;
                        &lt;li&gt;systemd --user&lt;/li&gt;
                        &lt;li&gt;service_user1000_1.service&lt;/li&gt;
                        &lt;li&gt;service_user1000_2.service&lt;/li&gt;
                        &lt;li&gt;service_user1000_3.service&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;li&gt;user-1001.slice
                &lt;ul&gt;
                &lt;li&gt;session-c4.scope
                        &lt;ul&gt;
                        &lt;li&gt;Programme 1&lt;/li&gt;
                        &lt;li&gt;Programme 2&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;session-c5.scope&lt;/li&gt;
                &lt;li&gt;session-c6.scope&lt;/li&gt;
                &lt;li&gt;user@1001.service
                        &lt;ul&gt;
                        &lt;li&gt;systemd --user&lt;/li&gt;
                        &lt;li&gt;service_user1001_1.service&lt;/li&gt;
                        &lt;li&gt;service_user1001_2.service&lt;/li&gt;
                        &lt;li&gt;service_user1001_3.service&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On remarque que les services de l'utilisateur sont démarrés dans un contexte
distinct de la session. Il faudra donc faire attention à la propagation des
variables d'environnement.&lt;/p&gt;

Dès que toutes les `session-c*.scope` d'un utilisateur sont
quittées, le service `user@.service` correspondant s'arrête
également, et avec tous les sous-services.  C'est un point important à
noter&amp;nbsp;! Par exemple, en l'état, utiliser les "timers" de systemd comme
remplacement à cron ne marchera pas&amp;nbsp;!&lt;br /&gt;
Heureusement, on peut passer outre et s'en sortir quand même. On verra plus bas
comment faire

&lt;h2&gt;Les services utilisateurs&lt;/h2&gt;
&lt;h3&gt;Comparaison&lt;/h3&gt;
&lt;p&gt; Les services utilisateurs sont gérés exactement de la même façon que les
services système, à ceci près que les unités (&lt;q class="quoteme"&gt;unit&lt;/q&gt;) sont
recherchées dans des dossiers différents (cf. &lt;code&gt;man systemd.unit&lt;/code&gt;). Au
lancement de &lt;code&gt;systemd --user&lt;/code&gt;, c'est l'unité
&lt;code&gt;default.target&lt;/code&gt; qui est lancée et qui lancera à son tour les
services nécessaires.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;systemctl --user&lt;/code&gt; et &lt;code&gt;dbus&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Les services gérés par systemd (qu'ils soient système ou utilisateur) se gèrent
essentiellement via la commande &lt;code&gt;systemctl&lt;/code&gt; (&lt;code&gt;--user&lt;/code&gt;),
qui dépend fortement de dbus. La première chose à faire est donc de s'assurer
que &lt;code&gt;dbus&lt;/code&gt; tourne, aussi bien au niveau système (&lt;q
class="quoteme"&gt;system bus&lt;/q&gt; pour dbus) qu'au niveau utilisateur (&lt;q
class="quoteme"&gt;session bus&lt;/q&gt;). Pour la partie système, on va se contenter
d'ajouter une dépendance à &lt;code&gt;user@.service&lt;/code&gt;. On va également
normaliser le chemin du socket pour le &lt;q class="quoteme"&gt;session bus&lt;/q&gt; en
l'indiquant dans la variable d'environnement appropriée
&lt;code&gt;DBUS_SESSION_BUS_ADDRESS&lt;/code&gt;. Comme user@.service est parent de tous
les services de l'utilisateur, on va l'utiliser pour transmettre cette variable
aussi&amp;nbsp;:&lt;/p&gt;

    :::bash hl_lines="3 6"
    # /etc/systemd/system/user@.service.d/dbus_env.conf
    [Unit]
    Wants=dbus.service

    [Service]
    Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/bus

&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;La ligne 2 du fichier indique qu'on souhaite que le service
&lt;code&gt;dbus&lt;/code&gt; système soit démarré, alors que la ligne 5 concerne la
variable d'environnement pour l'utilisateur. Ce sont donc &lt;q
class="quoteme"&gt;deux bus&lt;/q&gt; différents qu'on configure ici.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Dans ce qui suit, on va définir des différents services dont on aura besoin.
Ils peuvent être définis ou activés globalement ou à la discrétion de
l'utilisateur. Cela se fait soit selon l'endroit où ils sont placés
(&lt;code&gt;/etc/systemd/user/&lt;/code&gt; vs &lt;code&gt;$HOME/.config/systemd/user&lt;/code&gt;)
soit selon la façon dont ils sont activés (avec &lt;code&gt;--global&lt;/code&gt; vs
&lt;code&gt;--user&lt;/code&gt;).  Ici je vais définir les services et sockets associés à
dbus globalement, mais ils seront ensuite activés ou non selon le choix de
l'utilisateur&amp;nbsp;:&lt;/p&gt;

    :::bash
    # /etc/systemd/user/dbus.service
    [Unit]
    Description=D-Bus Message Bus
    Requires=dbus.socket

    [Service]
    ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
    ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
    Restart=always
    RestartSec=1

&lt;p&gt;(on notera que la principale différence avec le service système de même nom est
dans l'utilisation de &lt;code&gt;--session&lt;/code&gt; au lieu de
&lt;code&gt;--system&lt;/code&gt;)&lt;/p&gt;

    :::bash
    # /etc/systemd/user/dbus.socket
    [Unit]
    Description=D-Bus Message Bus Socket
    Before=sockets.target

    [Socket]
    ListenStream=/run/user/%U/bus

    [Install]
    WantedBy=default.target

&lt;p&gt;(Pour rappel, &lt;code&gt;default.target&lt;/code&gt; est la cible activée par défaut par
systemd).&lt;/p&gt;


&lt;p&gt;À partir de là, l'essentiel est fait. On crée un fichier
&lt;code&gt;mes_services.target&lt;/code&gt; alias de
&lt;code&gt;default.target&lt;/code&gt;&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/mes_services.target
    [Unit]
    Description=Mes services
    Wants=dbus.service
    AllowIsolate=true

    [Install]
    Alias=default.target

&lt;p&gt;puis on crée des fichiers service ou autres cibles dans le même dossier.
Ensuite, on les active avec la commande &lt;code&gt;systemctl&lt;/code&gt;, fait
habituellement pour gérer les services systèmes, sauf qu'ici on ajoute
l'argument &lt;code&gt;--user&lt;/code&gt;. La suite du billet consistera essentiellement en
des astuces et des cas spécifiques intéressants.&lt;/p&gt;

&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Remarque importante&lt;/p&gt;
&lt;p class="c_important"&gt;La directive &lt;code&gt;After&lt;/code&gt; n'a pas le même sens pour un &lt;q
class="quoteme"&gt;service&lt;/q&gt; et pour un &lt;q class="quoteme"&gt;target&lt;/q&gt;. Un service
ne sera démarré qu'une fois que tous les services cités dans &lt;code&gt;After&lt;/code&gt;
sont prêts (pour la définition de &lt;q class="quoteme"&gt;être prêt&lt;/q&gt;, cf le
&lt;code&gt;man systemd.service&lt;/code&gt;, bloc &lt;code&gt;Type=&lt;/code&gt;), alors que pour un
target il considère que les services cités &lt;em&gt;font partie&lt;/em&gt; de lui (et
peuvent donc être démarrés en même temps que d'autres services du target).
Dans certains des cas présentés dans la suite cette distinction prend sens.&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Des services utilisateur qui durent&lt;/h2&gt;
&lt;p&gt;Par défaut, les services associés à un utilisateur (tout ce qui est sous
&lt;code&gt;user@1001.service&lt;/code&gt; dans l'arborescence ci-dessus) sont arrêtés
lorsque l'utilisateur se déconnecte de toutes ses sessions, notamment les timers
qu'on aimerait utiliser comme remplacement à la crontab.&lt;/p&gt;

&lt;p&gt;Passer outre se fait avec la commande suivante&amp;nbsp;:&lt;/p&gt;

    :::bash
    loginctl enable-linger user

&lt;p&gt;Dans ce cas, &lt;code&gt;user@.service&lt;/code&gt; sera démarré dès le boot pour
l'utilisateur correspondant, même lorsque celui-ci n'est pas connecté.&lt;/p&gt;

&lt;p&gt;Je n'entre pas dans les détails sur comment définir l'équivalent des crontabs
avec systemd, c'est très bien expliqué dans les pages de manuel et sur les sites
dédiés à systemd (ou &lt;code&gt;man systemd.timer&lt;/code&gt;). L'astuce ci-dessus règle
le problème d'avoir des crontab qui durent pour un utilisateur même lorsque
celui-ci n'est pas connecté.&lt;/p&gt;

&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Remarque importante&lt;/p&gt;
&lt;p class="c_important"&gt;Pour les mails envoyés par les crontabs, c'est une autre
histoire. À ma connaissance les services de systemd loggent tout dans le
journal, et aucun mail ne peut être programmé directement avec les services de
systemd&lt;/p&gt; &lt;/div&gt;

&lt;h2 id="article_variables"&gt;Les variables d'environnement&lt;/h2&gt;
&lt;p&gt;Les variables d'environnement peuvent devenir un vrai casse-tête lorsqu'on
utilise les services&amp;nbsp;: comment transmettre les variables d'environnement
nécessaires aux services, par exemple GPG_AGENT_INFO ou SSH_AUTH_SOCK ou même
DISPLAY. Une des façons de faire est de spécifier dans le fichier du service
une directive de la forme&lt;/p&gt;

    :::bash
    Environment=DISPLAY=:0

ou

    :::bash
    EnvironmentFile=/fichier/a/charger

&lt;p&gt;Le problème est que cette configuration est statique et doit être définie pour
chaque service ou globalement dans un fichier
&lt;code&gt;/etc/systemd/system/user@.service.d/environment.conf&lt;/code&gt;. On perd le
&lt;q class="quoteme"&gt;dynamisme&lt;/q&gt; habituel des scripts de configuration.&lt;/p&gt;

&lt;p&gt;Ici, on va faire usage de la commande &lt;code&gt;systemctl --user
import-environment&lt;/code&gt; pour pallier ce problème. Cette commande permet
d'importer des variables d'environnement, qui seront incluses dans les services
démarrés &lt;em&gt;par la suite&lt;/em&gt;. On commence par créer un service setenv.service
qui va s'occuper de démarrer un script pour définir l'environnement. En ce qui
me concerne je définis un environnement différent lorsque je suis en ligne de
commande ou en graphique, du coup mon service dépend également de
cela&amp;nbsp;:&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/setenv@.service
    [Unit]
    Description=Set environment
    Wants=dbus.service gpg-agent.service ssh-agent.service
    After=dbus.service gpg-agent.service ssh-agent.service

    [Service]
    Type=oneshot
    Environment=SSH_AUTH_SOCK=%t/ssh_auth_sock
    ExecStart=%h/bin/systemd_setenv %i

&lt;p&gt;et j'active les services &lt;code&gt;setenv@type.service&lt;/code&gt; selon les besoins.
Ici par exemple, j'ai aussi défini une variable d'environnement pour le service.
La raison est que la partie "%t" (/run/user/1000/) est plus facile à trouver
dans ce fichier que dans un script... Il ne faudra juste pas oublier de
l'appliquer dans le script ensuite.&lt;/p&gt;

&lt;p&gt;Voici un exemple de script pour définir l'environnement&amp;nbsp;:&lt;/p&gt;

    :::bash
    # $HOME/bin/systemd_setenv
    #!/bin/zsh

    if [ "x$1" = "xcommun" ]; then
            . /etc/zsh/zprofile
            source $HOME/.gpg-agent-info
            export GPG_AGENT_INFO
            systemctl --user import-environment
            systemctl --user unset-environment PWD OLDPWD SHLVL _ MANAGERPID
    elif [ "x$1" = "xgraphique" ]; then
            export XDG_CONFIG_HOME="$HOME/.config/"
            export SAL_USE_VCLPLUGIN=gtk
            export XDG_MENU_PREFIX="lxde-"
            export DISPLAY=:0
            systemctl --user import-environment XDG_CONFIG_HOME SAL_USE_VCLPLUGIN XDG_MENU_PREFIX DISPLAY
    fi

Ici j'ai deux environnements différents selon que j'ai démarré une session
graphique ou juste une invite en ligne de commande. À noter que même si je
quitte l'environnement graphique, les variables définies par ce moyen restent
définies pour les services démarrés par la suite... On pourrait utiliser la
commande

    :::bash
    systemctl --user unset-environment VARIABLE1 VARIABLE2

&lt;p&gt;de la même façon pour détruire les variables après utilisation (auquel cas il
faut adapter le service setenv pour qu'il appelle un autre script — ou le même
avec des arguments différents — lorsqu'on quitte l'interface graphique).&lt;/p&gt;

&lt;h2&gt;Les &lt;code&gt;*-agent&lt;/code&gt;s&lt;/h2&gt;
&lt;p&gt;Des services qui vallent le coup d'être démarrés, peu importe le type de session
(graphique ou console ou distant) sont notamment les services
&lt;code&gt;ssh-agent&lt;/code&gt; et &lt;code&gt;gpg-agent&lt;/code&gt;. Il faut cependant penser à
transmettre les variables d'environnement aux processus intéressés (cf. &lt;a
href="#article_variables"&gt;La section correspondante&lt;/a&gt; pour plus
d'informations).&lt;/p&gt;

&lt;p&gt;Le service &lt;a href="https://github.com/vodik/envoy"&gt;envoy&lt;/a&gt; peut être
utilisé pour gérer ces agents. Personnellement je préfère séparer les deux
agents, ce qui n'est pas possible avec envoy.&lt;/p&gt;

&lt;p&gt;Pour &lt;code&gt;ssh-agent&lt;/code&gt;, on peut indiquer directement dans la commande
d'exécution à quel endroit on souhaite mettre le socket, ce qui facilite les
choses&amp;nbsp;:&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/ssh-agent.service
    [Unit]
    Description=ssh-agent
    ConditionFileIsExecutable=/usr/bin/ssh-agent

    [Service]
    ExecStart=/usr/bin/ssh-agent -d -a %t/ssh_auth_sock
    Restart=always

    [Install]
    WantedBy=mes_services.target

&lt;p&gt;Pour &lt;code&gt;gpg-agent&lt;/code&gt;, on ne peut que lui indiquer qu'on souhaite
enregistrer les informations (les variables d'environnement) dans un fichier, et
on ne peut pas forcer le socket à être placée à un endroit prévisible.&lt;/p&gt;

    :::bash
    # $HOME/.config/systemd/user/gpg-agent.service
    [Unit]
    Description=gpg-agent
    ConditionFileIsExecutable=/usr/bin/gpg-agent

    [Service]
    ExecStart=/usr/bin/gpg-agent --daemon --write-env-file %h/.gpg-agent-info
    Type=forking
    Restart=always

    [Install]
    WantedBy=mes_services.target

On peut ensuite charger le fichier &lt;code&gt;$HOME/.gpg-agent-info&lt;/code&gt; pour avoir
accès à l'agent.

    :::bash
    source $HOME/.gpg-agent-info

&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;Le fait de ne pas avoir un emplacement standard peut poser
problème si par exemple l'agent redémarre&amp;nbsp;: selon toute probabilité, le
socket ne sera pas au même endroit par la suite et les programmes déjà lancés ne
sauront pas où contacter l'agent.&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Utiliser systemd pour gérer sa session graphique&lt;/h2&gt;
&lt;p&gt;Il peut être tentant d'utiliser systemd pour gérer également sa session
graphique&amp;nbsp;: définir son gestionnaire de fenêtre préféré comme un service et
pouvoir l'arrêter et switcher vers un autre gestionnaire de fenêtre à volonté
sans avoir à redémarrer sa session. On verra plus tard que cela peut poser de
nouveaux problèmes.&lt;/p&gt;

&lt;h3&gt;Session graphique comme service&lt;/h3&gt;
&lt;p&gt;Le plus simple dans ce cas est de définir une unité
&lt;code&gt;graphical.target&lt;/code&gt; (ou &lt;code&gt;graphical@.target&lt;/code&gt; si on veut
définir plusieurs gestionnaires de fenêtre) et de l'activer dans le fichier
&lt;code&gt;.xsession&lt;/code&gt; (ou autre selon ce qui est exécuté pour la session).&lt;br
/&gt;
Il peut être nécessaire d'avoir les variables d'environnement correctement
définies à ce moment là, auquel cas chaque unité devra avoir le service
&lt;code&gt;setenv@graphical.service&lt;/code&gt; activé (comme indiqué précédemment, il ne
suffit pas de le mettre en &lt;code&gt;After&lt;/code&gt; dans le fichier graphical.target
pour qu'il soit activé avant les autres).&lt;/p&gt;
&lt;p&gt;Définir une session graphique comme service peut sembler appréciable. Deux
problèmes se posent cependant&amp;nbsp;:&lt;br /&gt;
Le premier est que systemctl retourne immédiatement. Ainsi, un fichier
&lt;code&gt;.xsession&lt;/code&gt; contenant uniquement&lt;/P&gt;

    :::bash
    # $HOME/.xsession
    export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
    systemctl --user start graphical.target

&lt;p&gt;ne sera pas suffisante, sous peine de voir sa session graphique disparaître à
peine commencée (note: le &lt;code&gt;export DBUS_SESSION_BUS_ADDRESS&lt;/code&gt; est
nécessaire pour le dialogue avec &lt;code&gt;systemd&lt;/code&gt;). Il existe des programmes
tels que &lt;a href="https://github.com/Stebalien/systemd-wait"&gt;systemd-wait&lt;/a&gt;
qui vont attendre la fin d'un service donné et peut être utilisé (selon le type
de session).&lt;br /&gt;&lt;br /&gt;
Le deuxième problème est plus ennuyeux&amp;nbsp;: il vient de la distinction entre
la session utilisateur elle-même et les services. Si on ne fait pas attention,
on risque de se retrouver avec quelque chose comme ça&amp;nbsp;:
&lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;systemd-wait -q --user graphique.service failed inactive&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;user@1000.service
                        &lt;ul&gt;
                        &lt;li&gt;systemd --user&lt;/li&gt;
                        &lt;li&gt;graphique.service
                                &lt;ul&gt;
                                &lt;li&gt;openbox&lt;/li&gt;
                                &lt;li&gt;firefox&lt;/li&gt;
                                &lt;li&gt;xterm&lt;/li&gt;
                                &lt;li&gt;xterm&lt;/li&gt;
                                &lt;/ul&gt;
                        &lt;/li&gt;
                        &lt;li&gt;service_2.service&lt;/li&gt;
                        &lt;li&gt;service_3.service&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
Pourquoi ça peut être gênant&amp;nbsp;? Parce que essentiellement le seul
programme ici qui est considéré comme &lt;q class="quoteme"&gt;actif&lt;/q&gt; est le
programme &lt;code&gt;systemd-wait&lt;/code&gt; qu'on a mis dans le &lt;code&gt;.xsession&lt;/code&gt;.
Un peu plus en détails sur ce que ça implique dans la &lt;a href="#polkit"&gt;section
suivante sur polkit&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Note à propos de &lt;code&gt;slim&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Comme précisé sur le site d'Archlinux, &lt;code&gt;slim&lt;/code&gt; n'est pas compatible
avec &lt;code&gt;systemd --user&lt;/code&gt; (du moins il ne l'était pas au moment de l'écriture de
cet article). Qu'est-ce que cela signifie concrètement, et que peut-on y
faire&amp;nbsp;?&lt;/p&gt;
&lt;p&gt;Premièrement, un petit zoom sur le fonctionnement de &lt;code&gt;slim&lt;/code&gt;.
&lt;code&gt;slim&lt;/code&gt; est un gestionnaire de connexion, c'est-à-dire de façon
simplifiée un équivalent du login dans les tty mais en graphique. Cela a
plusieurs implications&amp;nbsp;: il doit s'occuper de démarrer un serveur X, et de
démarrer la session de l'utilisateur après la connexion. Mais il doit aussi
reprendre la main quand l'utilisateur s'en va.&lt;/p&gt;
&lt;p&gt;Au moment de la connexion de l'utilisateur (via la configuration dans pam),
slim démarre une instance de &lt;code&gt;systemd --user&lt;/code&gt;, ainsi qu'un script de
l'utilisateur. Il ne démarre pas de serveur X puisqu'il est déjà démarré.&lt;br /&gt;
Au moment de la déconnexion cependant, il ne redémarre pas tout et réutilise
l'état dans lequel il était. Du point de vue de systemd, slim passe donc dans le
"scope" de l'utilisateur précédent (même s'il est toujours lancé par root):&lt;/p&gt;
&lt;div style="float:left"&gt;
&lt;p&gt;Avant déconnexion&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;system.slice
        &lt;ul&gt;
        &lt;li&gt;slimd.service
                &lt;ul&gt;
                &lt;li&gt;slim&lt;/li&gt;
                &lt;li&gt;X&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;user.slice
        &lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;...&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;user@1000.service&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div style="float:left"&gt;
&lt;p&gt;Après déconnexion&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;system.slice
        &lt;ul&gt;
        &lt;li&gt;slimd.service&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;user.slice
        &lt;ul&gt;
        &lt;li&gt;user-1000.slice
                &lt;ul&gt;
                &lt;li&gt;session-c1.scope
                        &lt;ul&gt;
                        &lt;li&gt;slim&lt;/li&gt;
                        &lt;li&gt;X&lt;/li&gt;
                        &lt;/ul&gt;&lt;/li&gt;
                &lt;li&gt;user@1000.service&lt;/li&gt;
                &lt;/ul&gt;&lt;/li&gt;
        &lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;hr class="clear" /&gt;
&lt;p&gt;Ce comportement là est ennuyeux pour les sessions suivantes. Sous Archlinux,
slim a été patché pendant l'intervalle d'écriture de ce billet (depuis
&lt;code&gt;slim 1.3.6-4&lt;/code&gt;, 2014-04-21) pour éviter cela, en quittant
systématiquement slim à la fin d'une session (avec l'argument
&lt;code&gt;-nodaemon&lt;/code&gt;) et en ajoutant une directive &lt;code&gt;Restart&lt;/code&gt; à
l'unité systemd de slim.&lt;/p&gt;
&lt;div class="note"&gt;
&lt;p class="h_note"&gt;Note&lt;/p&gt;
&lt;p class="c_note"&gt;La directive Restart est &lt;q class="quoteme"&gt;on-failure&lt;/q&gt;,
mais le patch fait quitter slim avec une erreur.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Une autre solution si on n'est pas sous Archlinux et qu'on ne souhaite pas
patcher slim est de mettre une ligne dans &lt;code&gt;/etc/slim.conf&lt;/code&gt; de la
forme&lt;/p&gt;

    :::bash
    # /etc/slim.conf
    sessionstop_cmd        systemctl restart slim.service

&lt;p&gt;qui aura pour effet de redémarrer slim à la fin de chaque session (ce qui
revient essentiellement au même que le patch).&lt;/p&gt;


&lt;h2 id="polkit"&gt;Polkit et les droits d'administration&lt;/h2&gt;
&lt;p&gt;Systemd distingue deux types d'utilisateur, à savoir les utilisateurs
"actifs" et "inactifs". Par exemple si deux utilisateurs sont connectés
physiquement sur le même pc, un seul est réellement "actif". Il fait également
une distinction selon que l'utilisateur est local ou distant. L'information peut
être obtenue avec&lt;/p&gt;

    :::bash
    loginctl show-session "session"

&lt;p&gt;où &lt;code&gt;"session"&lt;/code&gt; est l'identifiant de la session (on peut lister les
sessions avec &lt;code&gt;loginctl list-sessions&lt;/code&gt;).&lt;br /&gt;
En particulier, et c'est là que ça va devenir important, un service est
&lt;em&gt;toujours&lt;/em&gt; inactif.&lt;/p&gt;

&lt;p&gt;Polkit est un service qui permet de donner, temporairement ou non, plus de
droits à un utilisateur. Ces droits sont classés selon l'état de l'utilisateur,
actif ou inactif ou autre.&lt;/p&gt;
&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Attention&lt;/p&gt;
&lt;p class="c_important"&gt;Polkit et systemd n'ont pas la même notion d'utilisateur
&lt;em&gt;actif&lt;/em&gt;&amp;nbsp;: pour polkit, un utilisateur actif/inactif est
local &lt;em&gt;et&lt;/em&gt; &lt;q class="quoteme"&gt;actif/inactif au sens de systemd&lt;/q&gt;. Tous
les autres sont &lt;q class="quoteme"&gt;any&lt;/q&gt; (en particulier les utilisateurs
distants).  Cette règle est hardcodée dans la fonction
&lt;code&gt;check_authorization_sync&lt;/code&gt; du fichier
&lt;code&gt;src/polkitbackend/polkitbackendinteractiveauthority.c&lt;/code&gt; du code
source de polkit&amp;nbsp;:&lt;/p&gt;
&lt;/div&gt;

    :::c
    if (session_is_local)
      {
        if (session_is_active)
          implicit_authorization = polkit_action_description_get_implicit_active (action_desc);
        else
          implicit_authorization = polkit_action_description_get_implicit_inactive (action_desc);
      }
    else
      {
        implicit_authorization = polkit_action_description_get_implicit_any (action_desc);
      }

&lt;p&gt;Je n'entrerai pas plus dans les détails sur polkit dans ce billet, mais on
remarque déjà qu'un &lt;code&gt;xterm&lt;/code&gt; démarré en tant que service et un démarré
directement (par exemple via le fichier &lt;code&gt;.xsession&lt;/code&gt;) n'auront pas les
mêmes droits du point de vue de polkit&amp;nbsp;! Il faut donc faire attention à
cela lorsqu'on souhaite utiliser &lt;code&gt;systemd --user&lt;/code&gt; comme gestionnaire
de session, car par exemple il sera incapable d'éteindre le pc sans
&lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;</content><category term="informatique"></category><category term="systemd"></category><category term="daemons"></category><category term="cron"></category><category term="session"></category></entry><entry><title>Bash TCP/UDP sockets</title><link href="https://www.immae.eu/blog/2014/04/06/bash-tcp-udp-sockets/" rel="alternate"></link><published>2014-04-06T17:00:00+02:00</published><updated>2014-04-06T17:00:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-04-06:/blog/2014/04/06/bash-tcp-udp-sockets/</id><summary type="html">&lt;p&gt;On peut ouvrir facilement avec bash un socket TCP ou UDP pour
communiquer avec un serveur distant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;/dev/tcp/192.168.0.13/8000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Remplacer l'ip et le port par ceux que vous voulez contacter. L'ip peut être remplacée par un nom de domaine valide).&lt;/p&gt;
&lt;p&gt;Ça marche …&lt;/p&gt;</summary><content type="html">&lt;p&gt;On peut ouvrir facilement avec bash un socket TCP ou UDP pour
communiquer avec un serveur distant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;/dev/tcp/192.168.0.13/8000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Remplacer l'ip et le port par ceux que vous voulez contacter. L'ip peut être remplacée par un nom de domaine valide).&lt;/p&gt;
&lt;p&gt;Ça marche dans les deux sens bien sûr :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;&amp;lt;&amp;gt;/dev/tcp/immae.eu/80
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-ne&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET /blog/ HTTP/1.1\nHost: immae.eu\nConnection: close\n\n&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;
cat&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="code-snippet"></category><category term="Bash"></category><category term="TCP"></category><category term="UDP"></category></entry><entry><title>Setup an IPv6 VPN with an OVH server</title><link href="https://www.immae.eu/blog/2014/04/02/setup-an-ipv6-vpn-with-an-ovh-server/" rel="alternate"></link><published>2014-04-02T19:20:00+02:00</published><updated>2014-04-02T19:20:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-04-02:/blog/2014/04/02/setup-an-ipv6-vpn-with-an-ovh-server/</id><summary type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This tutorial combines a solution to two different but related problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The desire that machines not necessarily adjacent belong to the same &lt;q
class="quoteme"&gt;LAN&lt;/q&gt;. This is typically the role of a &lt;abbr
title="Virtual Private Network"&gt;VPN&lt;/abbr&gt;&lt;/li&gt;
&lt;li&gt;The fact that the majority of the Internet (IPv4) today consists of
machines hidden behind subnets and therefore …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This tutorial combines a solution to two different but related problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The desire that machines not necessarily adjacent belong to the same &lt;q
class="quoteme"&gt;LAN&lt;/q&gt;. This is typically the role of a &lt;abbr
title="Virtual Private Network"&gt;VPN&lt;/abbr&gt;&lt;/li&gt;
&lt;li&gt;The fact that the majority of the Internet (IPv4) today consists of
machines hidden behind subnets and therefore is impossible to contact them
&lt;q class="quoteme"&gt;publicly&lt;/q&gt; without using port redirection (which
prevents then having two machines in the network providing the same service on
the same port).&lt;/li&gt;
&lt;/ul&gt;
&lt;!--
----
--&gt;
&lt;p&gt;In the specific case that I will discuss, I have a personal server (by OVH),
with a unique IPv4 address (&lt;code&gt;198.51.100.24&lt;/code&gt;), and a /64 IPv6 subnet
(&lt;code&gt;2001:db8:200:13::/64&lt;/code&gt;), both fixed.&lt;/p&gt;
&lt;p&gt;Besides that, I have several PCs with different configurations and Internet
access, more or less restricted, in different networks and not necessarily
connected to each other (not even in the same country) and I that I would like
to connect with a &lt;em&gt;virtual network&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To create the virtual network, we have two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Either we create a private IPv4 subnet (but then attention to headaches if
by chance the machine happens to be on an identical physical network&lt;/li&gt;
&lt;li&gt;Otherwise... We have access to no less than 2&lt;sup&gt;64&lt;/sup&gt; IPv6 addresses
via our OVH server that we can take advantage of!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Creating a virtual subnet&lt;/h2&gt;
&lt;p&gt;To create this network, I use &lt;a href="http://tinc-vpn.org/"&gt;tinc&lt;/a&gt;. This
program is quite simple, and intuitive once you understand what a VPN is.&lt;/p&gt;
&lt;p&gt;In this particular case, interconnectin our machines is quite simple: all of
them are able to contact the server (which has a public Ipv4), so we just need
to ask each of them to connect to the server. tinc will then take care the
interconnection!&lt;/p&gt;
&lt;h3&gt;Common part&lt;/h3&gt;
&lt;p&gt;This part has to be done on both the clients and the server of the VPN:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We start by installing tinc (via the software manager of our favorite
  distribution)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tinc is able to manage multiple VPN networks, in which case the different
  configurations go in separate subfolders of the form
  &lt;code&gt;/etc/tinc/NAME&lt;/code&gt; (&lt;code&gt;NAME&lt;/code&gt; doesn't have to be common among
  the different hosts of the same network)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On a Debian-like distribution, you need a file
  &lt;code&gt;/etc/tinc/nets.boot&lt;/code&gt; that contains the list of configurations
  that are automatically started at boot time (provided that the service is
  enabled)&lt;/li&gt;
&lt;li&gt;On a distribution that works with systemd, you need to enable separately
  each &lt;code&gt;tincd@NAME.service&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We create a file called &lt;code&gt;tinc.conf&lt;/code&gt; with at least:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="hll"&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HostName
&lt;/span&gt;&lt;span class="hll"&gt;&lt;span class="nv"&gt;Interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;vpn6
&lt;/span&gt;
&lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here &lt;code&gt;Name&lt;/code&gt; is the name of the host in the VPN, and
&lt;code&gt;Interface&lt;/code&gt; is the interface name associated to the VPN that will
be created.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It might be necessary to add a &lt;code&gt;Device&lt;/code&gt; line if the default
  value is incorrect.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# The tap device tinc will use.&lt;/span&gt;
&lt;span class="c1"&gt;# Default is /dev/tap0 for ethertap or FreeBSD,&lt;/span&gt;
&lt;span class="c1"&gt;# /dev/tun0 for Solaris and OpenBSD,&lt;/span&gt;
&lt;span class="c1"&gt;# and /dev/net/tun for Linux tun/tap device.&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nv"&gt;Device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/net/tun
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If necessary, load the tun module&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;modprobe&lt;span class="w"&gt; &lt;/span&gt;tun
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We then create the public/private key pair that will be used by the host:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tincd&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;NAME&lt;span class="w"&gt; &lt;/span&gt;-K
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Put the public part (.pub) in  &lt;code&gt;/etc/tinc/NAME/hosts/HostName&lt;/code&gt;
(publicly readable, create the hosts directory), and keep the private part in
&lt;code&gt;/etc/tinc/NAME/&lt;/code&gt; readable only by root.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;That's it for the common part.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Server part&lt;/h3&gt;
&lt;p&gt;The server part is the more complex one. Let's go into more details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tinc can run two scripts &lt;code&gt;tinc-up&lt;/code&gt; and &lt;code&gt;tinc-down&lt;/code&gt;
  if they are present (and executable) in
  &lt;code&gt;/etc/tinc/NAME/tinc-{up,down}&lt;/code&gt; when the service starts/stops. We
  need to add a few commands there:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-up&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/eth0/proxy_ndp
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/all/forwarding

ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;mtu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1280&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;txqueuelen&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;route&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::/80&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-down&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/eth0/proxy_ndp
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/all/forwarding

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Don't forget to change &lt;code&gt;eth0&lt;/code&gt; by the interface on which the IPv4 is
linked, and the IPv6 addresses by yours.&lt;br /&gt;
Here I chose to use only the part &lt;code&gt;2001:db8:200:13:1::/80&lt;/code&gt; for the
VPN, and to assign the first of it to the server.&lt;br /&gt;
The line &lt;code&gt;echo 1 &amp;gt; /proc/sys/net/ipv6/conf/eth0/proxy_ndp&lt;/code&gt; is
important in that case because we will only provide addresses in the
&lt;code&gt;/64&lt;/code&gt; part of it, and without this packets will not broadcast from
the outside of the VPN inward (conversely, if you want to remain closed in the
VPN, you can remove this line).&lt;br /&gt;
The explanation is a little unclear to me, but if I understood correctly the
last 64 bits of the address are assumed to be local and therefore not routed.
More specifically, when the server receives on &lt;code&gt;eth0&lt;/code&gt; a request of
the form &lt;q&gt;Where can I contact &lt;code&gt;2001:db8:200:13:1::42&lt;/code&gt;?&lt;/q&gt; (by the
OVH router to which it is linked), he will answer &lt;q&gt;me&lt;/q&gt; (under some
conditions that we will see afterwards), and then will follow it to it's target
inside of the VPN.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now the &lt;q class="quoteme"&gt;configuration&lt;/q&gt; part is done for the
  server. We'll have to tell him afterwards who are the clients. We should keep
  the file &lt;code&gt;/etc/tinc/Immae/hosts/HostName&lt;/code&gt; accessible since it will
  have to be transmitted to each of the clients.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Client part&lt;/h3&gt;
&lt;p&gt;I'll use here the term &lt;code&gt;ServerName&lt;/code&gt; to design the name of the
server as defined on line &lt;code&gt;Name&lt;/code&gt; of the configuration file
&lt;code&gt;tinc.conf&lt;/code&gt; on the server.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Get &lt;code&gt;/etc/tinc/Immae/hosts/ServerName&lt;/code&gt; on the server and put it
  in &lt;code&gt;/etc/tinc/Immae/hosts/&lt;/code&gt; (next to your own), edit it and add a
  line at the top of the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="hll"&gt;&lt;span class="nv"&gt;Address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Replace the ip address by the IPv4 address of the server, or possibly its
domain name)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit the file &lt;code&gt;tinc.conf&lt;/code&gt; and add the informations for him to
  connect to the server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# The internet host to connect with.&lt;/span&gt;
&lt;span class="c1"&gt;# Comment these out to make yourself a listen-only connection&lt;/span&gt;
&lt;span class="c1"&gt;# You must use the name of another tinc host.&lt;/span&gt;
&lt;span class="c1"&gt;# May be used multiple times for redundance.&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nv"&gt;ConnectTo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ServerName
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We will also create files &lt;code&gt;tinc-up&lt;/code&gt; and &lt;code&gt;tinc-down&lt;/code&gt;
  as on the server, but now we don't need to activate a proxy of forward:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-up&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;mtu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1280&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;route&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;default&lt;span class="w"&gt; &lt;/span&gt;via&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-down&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;down
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be careful of course not to chose the same ip for two clients of the same
VPN.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Client-Server connexion&lt;/h3&gt;
&lt;p&gt;Here I use &lt;code&gt;ClientName&lt;/code&gt; to designate the name chosen by a client.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Now we need to inform the server that the client is authorized in the VPN.
  For that, we send the file &lt;code&gt;/etc/tinc/NAME/hosts/ClientName&lt;/code&gt; from the
  client to the server in the corresponding directory (keep the same name).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, we need to create two (executable) files &lt;code&gt;ClientName-up&lt;/code&gt;
  and &lt;code&gt;ClientName-down&lt;/code&gt; in the subfolder &lt;code&gt;hosts/&lt;/code&gt; on the
  server to set up and destroy the proxy when the client comes and goes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# hosts/NomDuClient-up&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# hosts/NomDuClient-down&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;End, configuration details&lt;/h3&gt;
&lt;p&gt;Now you just need to start the different tinc services on the machines, and
everyone will be interconnected and be able to access to the IPv6 Internet! To
sum up, the folders &lt;code&gt;/etc/tinc/NAME/&lt;/code&gt; should look like that:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Server$ ls -1R /etc/tinc/NAME&lt;/span&gt;
/etc/tinc/NAME:
hosts
rsa_key.priv
tinc-down
tinc-up
tinc.conf

/etc/tinc/NAME/hosts:
Server
Client1
Client1-up
Client1-down
Client2
Client2-up
Client2-down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Client1$ ls -1R /etc/tinc/NAME&lt;/span&gt;
/etc/tinc/NAME:
hosts
rsa_key.priv
tinc-down
tinc-up
tinc.conf

/etc/tinc/NAME/hosts:
Server
Client1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr class="clear" /&gt;
&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Important note&lt;/p&gt;
&lt;p class="c_important"&gt;By default, recent Linux distribution give priority to
IPv6 for Internet connection. That means that &lt;em&gt;all&lt;/em&gt; the connections will
go through the server as soon as IPv6 is available for the requested service. To
avoid that, you can edit the file &lt;code&gt;/etc/gai.conf&lt;/code&gt;, in which a section
explains exactly how to do that (i.e. give priority to l'IPv4). Note that this
configuration can be triggered independently on each client (see below).&lt;/p&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;By default:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/gai.conf&lt;/span&gt;
&lt;span class="c1"&gt;#    Add another rule to the RFC 3484 precedence table.  See section 2.1&lt;/span&gt;
&lt;span class="c1"&gt;#    and 10.3 in RFC 3484.  The default is:&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#precedence  ::1/128       50&lt;/span&gt;
&lt;span class="c1"&gt;#precedence  ::/0          40&lt;/span&gt;
&lt;span class="c1"&gt;#precedence  2002::/16     30&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::/96          20&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::ffff:0:0/96  10&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#    For sites which prefer IPv4 connections change the last line to&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::ffff:0:0/96  100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To give priority to IPv4 connectivity:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/gai.conf&lt;/span&gt;
&lt;span class="c1"&gt;#    Add another rule to the RFC 3484 precedence table.  See section 2.1&lt;/span&gt;
&lt;span class="c1"&gt;#    and 10.3 in RFC 3484.  The default is:&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
precedence&lt;span class="w"&gt;  &lt;/span&gt;::1/128&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;
precedence&lt;span class="w"&gt;  &lt;/span&gt;::/0&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;
precedence&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2002&lt;/span&gt;::/16&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;
precedence&lt;span class="w"&gt; &lt;/span&gt;::/96&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::ffff:0:0/96  10&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#    For sites which prefer IPv4 connections change the last line to&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
precedence&lt;span class="w"&gt; &lt;/span&gt;::ffff:0:0/96&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;</content><category term="informatique"></category><category term="Tinc"></category><category term="VPN"></category><category term="IPv6"></category></entry><entry><title>Installer un VPN en IPv6 avec un serveur OVH</title><link href="https://www.immae.eu/blog/2014/03/30/installer-un-vpn-en-ipv6-avec-un-serveur-ovh/" rel="alternate"></link><published>2014-03-30T22:20:00+02:00</published><updated>2014-03-30T22:20:00+02:00</updated><author><name>Immae</name></author><id>tag:www.immae.eu,2014-03-30:/blog/2014/03/30/installer-un-vpn-en-ipv6-avec-un-serveur-ovh/</id><summary type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Ce tutoriel combine une solution à deux problèmes différents mais assez
liés&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le fait de vouloir que des machines pas forcément voisines appartiennent au
même réseau &lt;q class="quoteme"&gt;local&lt;/q&gt;. C'est typiquement le rôle d'un
&lt;abbr title="Virtual Private Network"&gt;VPN&lt;/abbr&gt;&lt;/li&gt;
&lt;li&gt;Le fait que la majorité du réseau Internet (IPv4) de nos jours est
constitué de sous-réseaux …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Ce tutoriel combine une solution à deux problèmes différents mais assez
liés&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le fait de vouloir que des machines pas forcément voisines appartiennent au
même réseau &lt;q class="quoteme"&gt;local&lt;/q&gt;. C'est typiquement le rôle d'un
&lt;abbr title="Virtual Private Network"&gt;VPN&lt;/abbr&gt;&lt;/li&gt;
&lt;li&gt;Le fait que la majorité du réseau Internet (IPv4) de nos jours est
constitué de sous-réseaux cachés derrière des routeurs et qu'il est donc
impossible de contacter &lt;q class="quoteme"&gt;publiquement&lt;/q&gt; les machines
de ces sous-réseaux à moins d'avoir recours à des redirections de ports (ce qui
empêche du coup que deux machines du même réseau proposent le même service sur
le même port).&lt;/li&gt;
&lt;/ul&gt;
&lt;!--
----
--&gt;
&lt;p&gt;Dans le cas précis que je vais traiter, j'ai un serveur personnel (chez
OVH), possédant une unique adresse IPv4 (&lt;code&gt;198.51.100.24&lt;/code&gt;), et un /64
en IPv6 (&lt;code&gt;2001:db8:200:13::/64&lt;/code&gt;), toutes les deux fixes.&lt;/p&gt;
&lt;p&gt;À côté de ça, j'ai plusieurs PCs avec des configurations diverses et des
accès à Internet plus ou moins restreints, dans des réseaux différents et non
nécessairement connectés entre eux (voire pas dans le même pays) et que
j'aimerais relier par un &lt;em&gt;réseau virtuel&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Pour créer le réseau virtuel, deux possibilités s'offrent à nous&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Soit on crée un sous réseau IPv4 privé (mais alors attention aux maux de
têtes si par malheur on branche le pc sur un réseau physique identique)&lt;/li&gt;
&lt;li&gt;Sinon...On a accès à pas moins de 2&lt;sup&gt;64&lt;/sup&gt; adresses IPv6 via notre
serveur OVH, qu'on peut mettre à profit&amp;nbsp;!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Création d'un sous-réseau virtuel&lt;/h2&gt;
&lt;p&gt;Pour créer ce réseau, j'utilise &lt;a href="http://tinc-vpn.org/"&gt;tinc&lt;/a&gt;.
C'est un programme assez simple, et assez intuitif une fois qu'on a compris en
quoi consiste un VPN.&lt;/p&gt;
&lt;p&gt;Dans ce cas particulier, la façon d'interconnecter nos machines est assez
simple&amp;nbsp;: toutes sont capables de se connecter au serveur (qui a une IPv4
publique). Il suffit donc de demander à chacune de s'y connecter. tinc s'occupe
alors de l'interconnexion entre elles&amp;nbsp;!&lt;/p&gt;

&lt;h3&gt;Partie commune&lt;/h3&gt;
&lt;p&gt;Cette partie est à faire pour chacun des hôtes du VPN, que ce soit le client
ou le serveur&amp;nbsp;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;On commence par installer tinc (via les paquets de votre distribution
  préférée)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tinc est capable de gérer plusieurs réseaux VPN, auquel cas on sépare les
  dossier en créant un sous-dossier dans &lt;code&gt;/etc/tinc/NAME&lt;/code&gt; pour chaque
  configuration (&lt;code&gt;NAME&lt;/code&gt; n'a pas besoin d'être le même entre les
  différents hôtes)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sur une distribution de type Debian ou dérivé, il faut un fichier
  &lt;code&gt;/etc/tinc/nets.boot&lt;/code&gt; qui contienne la liste des dossiers qui sont
  démarrés automatiquement au démarrage (à condition que le service soit
  activé)&lt;/li&gt;
&lt;li&gt;Sur une distribution qui utilise systemd, il faut activer le(s)
  service(s) &lt;code&gt;tincd@NAME.service&lt;/code&gt; séparément.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On crée le fichier de configuration &lt;code&gt;tinc.conf&lt;/code&gt;, avec au
  minimum&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="hll"&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;NomDeLHote
&lt;/span&gt;&lt;span class="hll"&gt;&lt;span class="nv"&gt;Interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;vpn6
&lt;/span&gt;
&lt;span class="nv"&gt;Mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;switch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ici, &lt;code&gt;Name&lt;/code&gt; désigne le nom de l'hôte dans le réseau VPN, et
&lt;code&gt;Interface&lt;/code&gt; est le nom de l'interface associée au VPN qui sera
créée.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Il faut éventuellement ajouter une ligne &lt;code&gt;Device&lt;/code&gt; si la valeur
  par défaut n'est pas correcte.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# The tap device tinc will use.&lt;/span&gt;
&lt;span class="c1"&gt;# Default is /dev/tap0 for ethertap or FreeBSD,&lt;/span&gt;
&lt;span class="c1"&gt;# /dev/tun0 for Solaris and OpenBSD,&lt;/span&gt;
&lt;span class="c1"&gt;# and /dev/net/tun for Linux tun/tap device.&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nv"&gt;Device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/dev/net/tun
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Si nécessaire, charger le module tun&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;modprobe&lt;span class="w"&gt; &lt;/span&gt;tun
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On crée ensuite le couple clé publique/clé privée qu'on va utiliser pour
  l'hôte&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;tincd&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;NAME&lt;span class="w"&gt; &lt;/span&gt;-K
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Mettre la partie publique (en .pub) dans
&lt;code&gt;/etc/tinc/NAME/hosts/NomDeLHote&lt;/code&gt; (en lecture publique, créer le
dossier hosts), et garder la partie privée dans &lt;code&gt;/etc/tinc/NAME/&lt;/code&gt;
uniquement lisible par root.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Voilà pour la partie commune.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Partie serveur&lt;/h3&gt;
&lt;p&gt;La partie serveur est la partie la plus complexe. Plus en détails&amp;nbsp;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tinc peut lancer deux scripts &lt;code&gt;tinc-up&lt;/code&gt; et
  &lt;code&gt;tinc-down&lt;/code&gt; s'ils sont présents (et exécutables) dans
  &lt;code&gt;/etc/tinc/NAME/tinc-{up,down}&lt;/code&gt; au moment du démarrage/de l'arrêt du
  serveur. Ici, on va avoir besoin d'ajouter quelques commandes&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-up&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/eth0/proxy_ndp
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/all/forwarding

ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;mtu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1280&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;txqueuelen&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;route&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::/80&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;et&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-down&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/eth0/proxy_ndp
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/proc/sys/net/ipv6/conf/all/forwarding

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Penser à remplacer &lt;code&gt;eth0&lt;/code&gt; par l'interface sur laquelle arrive
l'IPv4, et les IPv6 par les vôtres.&lt;br /&gt;
Ici, j'ai fait le choix de n'utiliser que la partie
&lt;code&gt;2001:db8:200:13:1::/80&lt;/code&gt; pour le VPN, et d'assigner au VPN la
première de ces adresses.&lt;br /&gt;
La ligne &lt;code&gt;echo 1 &amp;gt; /proc/sys/net/ipv6/conf/eth0/proxy_ndp&lt;/code&gt; est
importante dans ce cas précis car on ne va donner des adresses que dans la
partie en &lt;code&gt;/64&lt;/code&gt; de l'adresse et sans ça les paquets ne seront pas
retransmis de l'extérieur du VPN vers l'intérieur (à l'inverse, si on veut
rester fermé dans le VPN, on peut enlever cette ligne).&lt;br /&gt;
L'explication est un peu floue pour moi, mais si j'ai bien compris les 64
derniers bits de l'adresse sont censés être locaux et donc non routés. Plus
précisément, quand le serveur recevra sur &lt;code&gt;eth0&lt;/code&gt; une demande de la
forme &lt;q&gt;où puis-je contacter &lt;code&gt;2001:db8:200:13:1::42&lt;/code&gt;&amp;nbsp;?&lt;/q&gt;
(par le routeur d'OVH auquel il est attaché), il répondra &lt;q&gt;c'est moi&lt;/q&gt;
(sous certaines conditions, on verra ensuite), puis il fera suivre à qui de
droit dans le VPN.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Voilà, la partie &lt;q class="quoteme"&gt;configuration&lt;/q&gt; pour le serveur
  est essentiellement finie.  Il va falloir lui faire connaître ensuite chacun
  des clients du VPN. On peut mettre de côté le fichier
  &lt;code&gt;/etc/tinc/Immae/hosts/NomDeLHote&lt;/code&gt; car on va devoir le transmettre à
  chacun des clients&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Partie client&lt;/h3&gt;
&lt;p&gt;J'utilise ici le terme &lt;code&gt;NomDuServeur&lt;/code&gt; pour désigner le nom du
serveur tel qu'on l'a défini à la ligne &lt;code&gt;Name&lt;/code&gt; dans le fichier
&lt;code&gt;tinc.conf&lt;/code&gt; pour le serveur.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Récupérer &lt;code&gt;/etc/tinc/Immae/hosts/NomDuServeur&lt;/code&gt; sur le serveur et
  le mettre dans &lt;code&gt;/etc/tinc/Immae/hosts/&lt;/code&gt; (à côté du sien), l'éditer
  et ajouter une ligne au début&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="hll"&gt;&lt;span class="nv"&gt;Address&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;198&lt;/span&gt;.51.100.24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Remplacer l'ip par l'adresse IPv4 du serveur, ou éventuellement son nom de
domaine)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Éditer le fichier &lt;code&gt;tinc.conf&lt;/code&gt; et ajouter les informations pour
  qu'il se connecte au serveur&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# The internet host to connect with.&lt;/span&gt;
&lt;span class="c1"&gt;# Comment these out to make yourself a listen-only connection&lt;/span&gt;
&lt;span class="c1"&gt;# You must use the name of another tinc host.&lt;/span&gt;
&lt;span class="c1"&gt;# May be used multiple times for redundance.&lt;/span&gt;
&lt;span class="hll"&gt;&lt;span class="nv"&gt;ConnectTo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;NomDuServeur
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On va également créer des fichiers &lt;code&gt;tinc-up&lt;/code&gt; et
  &lt;code&gt;tinc-down&lt;/code&gt; comme sur le serveur, mais cette fois on n'a pas besoin
  d'activer de proxy ni de forward&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-up&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;mtu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1280&lt;/span&gt;
&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;route&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;default&lt;span class="w"&gt; &lt;/span&gt;via&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;et&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# tinc-down&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42/96&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;-6&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INTERFACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;down
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il faut bien sûr faire attention à ne pas prendre deux fois la même ip pour
deux clients différents du VPN.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Connexion Client-Serveur&lt;/h3&gt;
&lt;p&gt;J'utilise ici &lt;code&gt;NomDuClient&lt;/code&gt; pour désigner le nom choisi par un
client.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Maintenant il faut faire savoir au serveur que le client est autorisé, pour
  cela il faut envoyer le fichier &lt;code&gt;/etc/tinc/NAME/hosts/NomDuClient&lt;/code&gt;
  du client vers le serveur dans le dossier correspondant (en conservant le nom
  du fichier).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finalement, il faut créer deux fichiers (exécutables) &lt;code&gt;NomDuClient-up&lt;/code&gt; et
  &lt;code&gt;NomDuClient-down&lt;/code&gt; dans le dossier &lt;code&gt;hosts/&lt;/code&gt; sur le
  serveur pour mettre en place et détruire le proxy lorsque le client apparaît et
  disparaît&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# hosts/NomDuClient-up&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;et&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# hosts/NomDuClient-down&lt;/span&gt;
&lt;span class="c1"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="hll"&gt;ip&lt;span class="w"&gt; &lt;/span&gt;neigh&lt;span class="w"&gt; &lt;/span&gt;del&lt;span class="w"&gt; &lt;/span&gt;proxy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2001&lt;/span&gt;:db8:200:13:1::42&lt;span class="w"&gt; &lt;/span&gt;dev&lt;span class="w"&gt; &lt;/span&gt;eth0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fin, détails de configuration&lt;/h3&gt;
&lt;p&gt;Plus qu'à démarrer les différents services tinc sur les machines, et tout le
monde sera interconnecté et pourra accéder au net en IPv6&amp;nbsp;! Pour résumer, les
répertoires &lt;code&gt;/etc/tinc/NAME/&lt;/code&gt; devraient ressembler à ça&amp;nbsp;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Serveur$ ls -1R /etc/tinc/NAME&lt;/span&gt;
/etc/tinc/NAME:
hosts
rsa_key.priv
tinc-down
tinc-up
tinc.conf

/etc/tinc/NAME/hosts:
Serveur
Client1
Client1-up
Client1-down
Client2
Client2-up
Client2-down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;et&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Client1$ ls -1R /etc/tinc/NAME&lt;/span&gt;
/etc/tinc/NAME:
hosts
rsa_key.priv
tinc-down
tinc-up
tinc.conf

/etc/tinc/NAME/hosts:
Serveur
Client1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr class="clear" /&gt;
&lt;div class="important"&gt;
&lt;p class="h_important"&gt;Remarque importante&lt;/p&gt;
&lt;p class="c_important"&gt;Par défaut, les distributions
récentes de Linux donnent priorité à l'IPv6 pour les connexions Internet. Cela
signifie concrètement que toutes les connexions vont passer en priorité par
votre serveur dès lors que l'IPv6 est disponible pour le service demandé. Pour
éviter cela, on peut éditer le fichier &lt;code&gt;/etc/gai.conf&lt;/code&gt;, dans lequel
une section explique justement comment faire (i.e. donner priorité à l'IPv4).
Notez que cette configuration se fait au choix sur chaque client indépendamment
(voir ci-dessous).&lt;/p&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Par défaut&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/gai.conf&lt;/span&gt;
&lt;span class="c1"&gt;#    Add another rule to the RFC 3484 precedence table.  See section 2.1&lt;/span&gt;
&lt;span class="c1"&gt;#    and 10.3 in RFC 3484.  The default is:&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#precedence  ::1/128       50&lt;/span&gt;
&lt;span class="c1"&gt;#precedence  ::/0          40&lt;/span&gt;
&lt;span class="c1"&gt;#precedence  2002::/16     30&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::/96          20&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::ffff:0:0/96  10&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#    For sites which prefer IPv4 connections change the last line to&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::ffff:0:0/96  100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pour donner priorité à l'IPv4&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# /etc/gai.conf&lt;/span&gt;
&lt;span class="c1"&gt;#    Add another rule to the RFC 3484 precedence table.  See section 2.1&lt;/span&gt;
&lt;span class="c1"&gt;#    and 10.3 in RFC 3484.  The default is:&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
precedence&lt;span class="w"&gt;  &lt;/span&gt;::1/128&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;
precedence&lt;span class="w"&gt;  &lt;/span&gt;::/0&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;
precedence&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2002&lt;/span&gt;::/16&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;
precedence&lt;span class="w"&gt; &lt;/span&gt;::/96&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;
&lt;span class="c1"&gt;#precedence ::ffff:0:0/96  10&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#    For sites which prefer IPv4 connections change the last line to&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
precedence&lt;span class="w"&gt; &lt;/span&gt;::ffff:0:0/96&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;</content><category term="informatique"></category><category term="Tinc"></category><category term="VPN"></category><category term="IPv6"></category></entry></feed>