diff --git a/group_vars/crans_server/vars.yml b/group_vars/crans_server/vars.yml
index 9d0200955d9f051a4bbdee5a0f0620ad2c2d0648..63212423c882f71ea90a20f69be866441b4363a1 100644
--- a/group_vars/crans_server/vars.yml
+++ b/group_vars/crans_server/vars.yml
@@ -9,3 +9,18 @@ debian_mirror: http://mirror.adm.crans.org/debian
 ubuntu_mirror: http://mirror.adm.crans.org/ubuntu
 debian_components: main non-free
 ubuntu_components: main restricted universe multiverse
+
+glob_borg:
+  to_backup:
+    - /etc
+    - /var
+  path: /backup/borg
+  remote:
+    - borg@zephir.adm.crans.org:/backup/borg/{{ ansible_hostname }}
+  retention:
+    - ["daily", 4]
+    - ["monthly", 6]
+  consistency_check:
+    - disabled
+  extra_init:
+    - make-parent-dirs
\ No newline at end of file
diff --git a/host_vars/zephir.adm.crans.org.yml b/host_vars/zephir.adm.crans.org.yml
new file mode 100644
index 0000000000000000000000000000000000000000..541870153a981b7f3f8755b854fe01121e8cce37
--- /dev/null
+++ b/host_vars/zephir.adm.crans.org.yml
@@ -0,0 +1,7 @@
+---
+
+loc_borg:
+  to_exclude:
+    - /var/lib/backuppc
+  remote:
+    - /backup/borg/zephir
diff --git a/hosts b/hosts
index a7ef2273e59b60f989712f7941e9db4aae4ddc08..7ed9d2a52d4c41317b4f9c3bb4a99aa766229cca 100644
--- a/hosts
+++ b/hosts
@@ -23,6 +23,9 @@
 # [test_vm]
 # re2o-test.adm.crans.org
 
+[backups]
+zephir.adm.crans.org
+
 [certbot]
 gitzly.adm.crans.org
 
diff --git a/plays/backup.yml b/plays/backup.yml
index 7d4681003714b72abccf903e7283c3094446d047..1949a5ca9821bd29b6a11b762a67564e08dc8b1d 100755
--- a/plays/backup.yml
+++ b/plays/backup.yml
@@ -1,15 +1,15 @@
 #!/usr/bin/env ansible-playbook
 ---
-# zephir backups virtual machines.
-# omnomnom backups home dirs.
 
-# Rsync client on all server to allow backup
-#- hosts: server
-#  vars:
-#    # Backup password
-#    backuppc_rsyncd_passwd: "{{ vault_backuppc_rsyncd_passwd }}"
-#  roles: ["rsync-client"]
+- hosts: server
+  vars:
+    borg: '{{ glob_borg | default({}) | combine(loc_borg | default({})) }}'
+    mirror: '{{ glob_mirror | default({}) | combine(loc_mirror | default({})) }}'
+  roles:
+    - borgbackup-client
 
-# Backuppc backup software
-#- hosts: zephir.adm.crans.org,omnomnom.adm.crans.org
-# roles: ["backuppc"]
+- hosts: backups
+  vars:
+    borg: '{{ glob_borg | default({}) | combine(loc_borg | default({})) }}'
+  roles:
+    - borgbackup-server
diff --git a/roles/borgbackup-client/handlers/main.yml b/roles/borgbackup-client/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6cd8da2ff530e84dae46a68b862003934bb38c90
--- /dev/null
+++ b/roles/borgbackup-client/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: restart cron
+  service:
+    name: cron
+    state: restarted
diff --git a/roles/borgbackup-client/tasks/main.yml b/roles/borgbackup-client/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2325ea277fd420a9144c7a25c05d2cee3bae6171
--- /dev/null
+++ b/roles/borgbackup-client/tasks/main.yml
@@ -0,0 +1,60 @@
+---
+- name: Pin borgmatic
+  template:
+    src: "apt/{{ item }}.j2"
+    dest: "/etc/apt/{{ item }}"
+  loop:
+    - sources.list.d/bullseye.list
+    - preferences.d/borgmatic-bullseye
+  when: ansible_lsb.release | int <= 10
+
+- name: Install borgbackup
+  apt:
+    update_cache: true
+    name:
+      - borgbackup
+      - borgmatic
+    state: present
+  register: apt_result
+  retries: 3
+  until: apt_result is succeeded
+
+- name: Ensures /etc/borgmatic exists
+  file:
+    path: /etc/borgmatic
+    state: directory
+    mode: 0700
+    owner: root
+  
+- name: Deploy ssh private key
+  template:
+    src: "borgmatic/id_ed25519_borg.j2"
+    dest: "/etc/borgmatic/id_ed25519_borg"
+    mode: 0600
+    owner: root
+
+- name: Deploy borgmatic config
+  template:
+    src: "borgmatic/config.yaml.j2"
+    dest: "/etc/borgmatic/config.yaml"
+    mode: 0600
+    owner: root
+    group: root
+
+- name: Init borg repository
+  command:
+    cmd: /usr/bin/borgmatic init -e repokey
+  register: borg_init
+  changed_when: '"does not exist" in borg_init.stderr'
+
+- name: Deploy borg cron
+  template:
+    src: "cron.d/borg.j2"
+    dest: "/etc/cron.d/borg"
+  notify: restart cron
+
+- name: Indicate role in motd
+  template:
+    src: update-motd.d/04-service.j2
+    dest: /etc/update-motd.d/04-borgbackup
+    mode: 0755
diff --git a/roles/borgbackup-client/templates/apt/preferences.d/borgmatic-bullseye.j2 b/roles/borgbackup-client/templates/apt/preferences.d/borgmatic-bullseye.j2
new file mode 100644
index 0000000000000000000000000000000000000000..32e59b73d3771cdfc5edb5aa491305a93de47d93
--- /dev/null
+++ b/roles/borgbackup-client/templates/apt/preferences.d/borgmatic-bullseye.j2
@@ -0,0 +1,12 @@
+{{ ansible_header | comment }}
+
+
+Package: *
+Pin: release n=bullseye
+Pin-Priority: 1
+
+
+Package: borgmatic
+Pin: release n=bullseye
+Pin-Priority: 900
+
diff --git a/roles/borgbackup-client/templates/apt/sources.list.d/bullseye.list.j2 b/roles/borgbackup-client/templates/apt/sources.list.d/bullseye.list.j2
new file mode 100644
index 0000000000000000000000000000000000000000..e8bbe8d247ff27563951c1d55e30db2189fba97e
--- /dev/null
+++ b/roles/borgbackup-client/templates/apt/sources.list.d/bullseye.list.j2
@@ -0,0 +1,3 @@
+{{ ansible_header | comment }}
+
+deb http://{{ mirror.name }}/debian bullseye main
diff --git a/roles/borgbackup-client/templates/borgmatic/config.yaml.j2 b/roles/borgbackup-client/templates/borgmatic/config.yaml.j2
new file mode 100644
index 0000000000000000000000000000000000000000..94750a2c7ac7e3017cd60f48927b9fe760197a16
--- /dev/null
+++ b/roles/borgbackup-client/templates/borgmatic/config.yaml.j2
@@ -0,0 +1,88 @@
+{{ ansible_header | comment }}
+
+location:
+    source_directories:
+{% for dir in borg.to_backup %}
+        - {{ dir }}
+{% endfor %}
+
+    repositories:
+{% for remote in borg.remote %}
+        - {{ remote }}
+{% endfor %}
+
+    exclude_patterns:
+        - '*.pyc'
+        - '\#*\#'
+        - '*~'
+{% for pattern in borg.to_exclude | default([]) %}
+        - {{ pattern }}
+{% endfor %}
+
+    exclude_caches: true
+
+    exclude_if_present:
+        - .nobackup
+
+    borgmatic_source_directory: /tmp/borgmatic
+
+storage:
+    encryption_passphrase: {{ vault_borgbackup_passwd }}
+    ssh_command: ssh -i /etc/borgmatic/id_ed25519_borg
+    borg_base_directory: /etc/borgmatic
+    borg_config_directory: /etc/borgmatic/config/
+    borg_cache_directory: /etc/borgmatic/cache
+    borg_security_directory: /etc/borgmatic/config/security
+    borg_keys_directory: /etc/borgmatic/config/keys
+    compression: 'lz4'
+    umask: 0077
+    lock_wait: 5
+    archive_name_format: '{hostname}-{now}'
+{% set extra_init = borg.extra_init | default([]) %}
+{% set extra_prune = borg.extra_prune | default([]) %}
+{% set extra_create = borg.extra_create | default([]) %}
+{% set extra_check = borg.extra_check | default([]) %}
+{% if extra_init or extra_prune or extra_create or extra_check %}
+    extra_borg_options:
+{% endif %}
+{% if extra_init %}
+        # Extra command-line options to pass to "borg init".
+        init: {% for cmd in extra_init %}--{{ cmd }} {% endfor %}
+{% endif %}
+{% if extra_prune  %}
+        # Extra command-line options to pass to "borg prune".
+        prune: {% for cmd in extra_prune  %}--{{ cmd }} {% endfor %}
+{% endif %}
+
+{% if extra_create %}
+        # Extra command-line options to pass to "borg create".
+        create: {% for cmd in extra_create %}--{{ cmd }} {% endfor %}
+{% endif %}
+
+{% if extra_check %}
+        # Extra command-line options to pass to "borg check".
+        check: {% for cmd in extra_check %}--{{ cmd }} {% endfor %}
+{% endif %}
+
+retention:
+{% for retention in borg.retention %}
+    keep_{{ retention[0] }}: {{ retention[1] }}
+{% endfor %}
+    prefix: '{hostname}-'
+
+consistency:
+    checks:
+{% for check in borg.consistency_check %}
+        - {{ check }}
+{% endfor %}
+
+{% if borg.hooks | default([]) %}
+  hooks:
+  {% for hook in borg.hooks %}
+    {{ hook.type }}:
+    {% for value in hook.values %}
+      - {{ value }}
+    {% endfor %}
+  {% endfor %}
+  umask: 0077
+{% endif %}
diff --git a/roles/borgbackup-client/templates/borgmatic/id_ed25519_borg.j2 b/roles/borgbackup-client/templates/borgmatic/id_ed25519_borg.j2
new file mode 100644
index 0000000000000000000000000000000000000000..1ef022e0994c22897203d5f3025f486fbf70edd8
--- /dev/null
+++ b/roles/borgbackup-client/templates/borgmatic/id_ed25519_borg.j2
@@ -0,0 +1 @@
+{{ vault_borgbackup_ssh_privkey }}
diff --git a/roles/borgbackup-client/templates/cron.d/borg.j2 b/roles/borgbackup-client/templates/cron.d/borg.j2
new file mode 100644
index 0000000000000000000000000000000000000000..41c84ebd340fe23903cb058b5b3df8fd11270c3e
--- /dev/null
+++ b/roles/borgbackup-client/templates/cron.d/borg.j2
@@ -0,0 +1,5 @@
+{{ ansible_header | comment }}
+
+PATH=$PATH:/usr/sbin:/usr/bin:/usr/local/bin:/sbin:/bin
+
+{{ 60 | random(seed=inventory_hostname) }} {{ 24 | random(seed=inventory_hostname) }} * * * root borgmatic --syslog-verbosity 1
diff --git a/roles/borgbackup-client/templates/update-motd.d/04-service.j2 b/roles/borgbackup-client/templates/update-motd.d/04-service.j2
new file mode 100755
index 0000000000000000000000000000000000000000..fcbc611dc308602bb6b657a90d5961f0adc7428b
--- /dev/null
+++ b/roles/borgbackup-client/templates/update-motd.d/04-service.j2
@@ -0,0 +1,3 @@
+#!/usr/bin/tail +14
+{{ ansible_header | comment }}
+> Borgbackup (Client) a été déployé sur cette machine. Voir /etc/borgmatic/.
diff --git a/roles/borgbackup-server/tasks/main.yml b/roles/borgbackup-server/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..052347d5261eb91d1afa313980336be853d26789
--- /dev/null
+++ b/roles/borgbackup-server/tasks/main.yml
@@ -0,0 +1,38 @@
+---
+- name: Install borgbackup
+  apt:
+    update_cache: true
+    name:
+      - borgbackup
+    state: present
+  register: apt_result
+  retries: 3
+  until: apt_result is succeeded
+
+- name: Create borgbackup user
+  user:
+    create_home: yes
+    home: '/var/lib/borg/'
+    system: yes
+    state: present
+    update_password: always
+    name: borg
+
+- name: Ensures .ssh dir exists
+  file:
+    path: /var/lib/borg/.ssh
+    state: directory
+    mode: 0700
+    owner: borg
+
+- name: Deploy authorized_keys
+  template:
+    src: "authorized_keys.j2"
+    dest: "/var/lib/borg/.ssh/authorized_keys"
+    mode: 0600
+
+- name: Indicate role in motd
+  template:
+    src: update-motd.d/05-service.j2
+    dest: /etc/update-motd.d/05-borg
+    mode: 0755
diff --git a/roles/borgbackup-server/templates/authorized_keys.j2 b/roles/borgbackup-server/templates/authorized_keys.j2
new file mode 100644
index 0000000000000000000000000000000000000000..9c3ff0ca0009e9ff6a40660d7e0cd5a065a7e060
--- /dev/null
+++ b/roles/borgbackup-server/templates/authorized_keys.j2
@@ -0,0 +1,3 @@
+{{ ansible_header | comment }}
+
+command="borg serve --restrict-to-path {{ borg.path }}",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding {{ vault_borgbackup_ssh_pubkey }}
diff --git a/roles/borgbackup-server/templates/update-motd.d/05-service.j2 b/roles/borgbackup-server/templates/update-motd.d/05-service.j2
new file mode 100755
index 0000000000000000000000000000000000000000..f27119aa58fb0b3c924ecf85c793a8d92d9f35c0
--- /dev/null
+++ b/roles/borgbackup-server/templates/update-motd.d/05-service.j2
@@ -0,0 +1,3 @@
+#!/usr/bin/tail +14
+{{ ansible_header | comment }}
+> Borgbackup (Serveur) a été déployé sur cette machine. Les backups sont situés dans {{ borg.path }}.