diff --git a/group_vars/horde.yml b/group_vars/horde.yml
new file mode 100644
index 0000000000000000000000000000000000000000..11ea19577bd20b9813390b1adfc84cb9c414aee7
--- /dev/null
+++ b/group_vars/horde.yml
@@ -0,0 +1,20 @@
+glob_horde:
+  secret: '{{ vault_horde_secret }}'
+  imap: imap.adm.crans.org
+  smtp: smtp.crans.org
+  maildomain: crans.org
+  db: thot.adm.crans.org
+  admins:
+    - "'paulon'"
+    - "'vulcain'"
+    - "'graillot'"
+    - "'bombar'"
+    - "'pa'"
+    - "'erdnaxe'"
+  redirection: https://wiki.crans.org/VieCrans/PagesDeDeconnexion/ERR_CHOOSE_WEBMAIL
+  src_hostname: horde.crans.org
+  dest_hostname : webmail.crans.org
+  admin_src_hostname : horde.adm.crans.org
+  admin_dest_hostname : webmail.adm.crans.org
+  zone_ipv4 : 10.231.136.0/24
+  zone_ipv6 : 2a0c:700:0:2::/64
diff --git a/host_vars/horde-srv.adm.crans.org.yml b/host_vars/horde-srv.adm.crans.org.yml
new file mode 100644
index 0000000000000000000000000000000000000000..54e2e5fc70e2001ccb847854836ae1449e1e08e8
--- /dev/null
+++ b/host_vars/horde-srv.adm.crans.org.yml
@@ -0,0 +1,2 @@
+loc_horde:
+  ipv6: '[2a0c:700:0:2:5474:8dff:fe5d:e2be]'
diff --git a/hosts b/hosts
index 49bd79fc1882d265d822e31e950a11f20fd487cc..e44a481d0d2b4cbcecb9be044805966bffe35335 100644
--- a/hosts
+++ b/hosts
@@ -4,6 +4,8 @@
 # > We name servers according to location, then type.
 # > Then we regroup everything in global geographic and type groups.
 
+[horde]
+horde-srv.adm.crans.org
 
 [dhcp]
 dhcp.adm.crans.org
diff --git a/plays/horde.yml b/plays/horde.yml
new file mode 100755
index 0000000000000000000000000000000000000000..bc775369a6ad54dd7b9f0f19ffabce723ec19b12
--- /dev/null
+++ b/plays/horde.yml
@@ -0,0 +1,6 @@
+#!/usr/bin/env ansible-playbook
+---
+# Moi j'aime le ocaml et lui il installe horde
+- hosts: horde
+  roles:
+    - horde
diff --git a/roles/horde/README.md b/roles/horde/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..874a42e6360c9d4cbc0f4ca9a8a447fecd79de32
--- /dev/null
+++ b/roles/horde/README.md
@@ -0,0 +1,26 @@
+# Horde
+Ce rôle ansible deploie une instance du webmail horde.
+
+## Variables
+  - glob_horde. :
+    - secret : le secret de horde
+    - imap : le serveur imap
+    - smtp : le serveur smtp (il doit juste être contactable depuis le serveur
+      imap)
+    - maildomain : le nom de domaine depuis qui envoyé les mails
+    - db : la bdd
+    - admins : la liste des admins de horde
+    - redirection : ou rediriger les utilisateurs si il essaie de voir la racine
+      du site
+    - src_hostname : on utilise deux hostnames, le premier va rediriger vers le
+      second. Ici c'est le premier
+    - dest_hostname : Ici c'est le second
+    - admin_src_hostname : même chose mais sur le réseau d'administration. Ici
+      c'est le premier
+    - admin_dest_hostname : Ici c'est le second
+    - zone_ipv4 : la zone ipv4 du réseaux sur lequel le proxy discute avec le
+      serveur
+    - zone ipv6 : la zone ipv6 du réseaux sur lequel le proxy discute avec le
+      serveur
+  - loc_horde :
+    - ipv6 : l'ipv6 du serveur
diff --git a/roles/horde/handlers/main.yml b/roles/horde/handlers/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..721ac46277352c921799f12ab301f743b8d676da
--- /dev/null
+++ b/roles/horde/handlers/main.yml
@@ -0,0 +1,6 @@
+---
+
+- name: Restart nginx
+  service:
+    name: nginx.service
+    state: restarted
diff --git a/roles/horde/tasks/main.yml b/roles/horde/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..55ab289100672e7bcb45f107ae8f70652123bcf4
--- /dev/null
+++ b/roles/horde/tasks/main.yml
@@ -0,0 +1,45 @@
+---
+# Setup dependencies
+- name: Install horde APT dependencies
+  apt:
+    update_cache: true
+    name:
+      - nginx
+      - php-horde-webmail
+  register: apt_result
+  retries: 3
+  until: apt_result is succeeded
+
+- name: Configure horde
+  template:
+    src: '{{ item }}.j2'
+    dest: '/etc/{{ item }}'
+    owner: www-data
+    group: www-data
+    mode: 0640
+  loop:
+    - horde/horde/conf.php
+    - horde/imp/backends.php
+
+- name: Configure nginx site
+  template:
+    src: '{{ item }}.j2'
+    dest: '/etc/{{ item }}'
+    owner: root
+    group: root
+    mode: 0644
+  loop:
+    - nginx/sites-available/webmail
+    - nginx/sites-available/horde
+    - nginx/snippets/php.conf
+  notify: Restart nginx
+
+- name: Enable nginx site
+  file:
+    src: '/etc/nginx/sites-available/{{ item }}'
+    dest: '/etc/nginx/sites-enabled/{{ item }}'
+    state: link
+  loop:
+    - webmail
+    - horde
+  notify: Restart nginx
diff --git a/roles/horde/templates/horde/horde/conf.php.j2 b/roles/horde/templates/horde/horde/conf.php.j2
new file mode 100644
index 0000000000000000000000000000000000000000..6da1cbab1bb264876c3f65d739b7b900a7aaf31b
--- /dev/null
+++ b/roles/horde/templates/horde/horde/conf.php.j2
@@ -0,0 +1,127 @@
+{{ ansible_header | comment(decoration='// ') }} 
+<?php
+/* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
+// $Id: 08fc885cd91fbae2d752e274b554c5f1645129c8 $
+$conf['vhosts'] = false;
+$conf['debug_level'] = E_ALL & ~E_NOTICE;
+$conf['max_exec_time'] = 0;
+$conf['compress_pages'] = true;
+$conf['secret_key'] = '{{ glob_horde.secret }}';
+$conf['umask'] = 077;
+$conf['testdisable'] = true;
+$conf['use_ssl'] = 1;
+$conf['server']['name'] = $_SERVER['SERVER_NAME'];
+$conf['urls']['token_lifetime'] = 30;
+$conf['urls']['hmac_lifetime'] = 30;
+$conf['urls']['pretty'] = false;
+$conf['safe_ips'] = array();
+$conf['session']['name'] = 'Horde';
+$conf['session']['use_only_cookies'] = true;
+$conf['session']['timeout'] = 0;
+$conf['session']['cache_limiter'] = 'nocache';
+$conf['session']['max_time'] = 72000;
+$conf['cookie']['domain'] = $_SERVER['SERVER_NAME'];
+$conf['cookie']['path'] = '/';
+$conf['sql']['username'] = 'www-data';
+$conf['sql']['hostspec'] = '{{ glob_horde.db }}';
+$conf['sql']['protocol'] = 'tcp';
+$conf['sql']['database'] = 'horde5';
+$conf['sql']['charset'] = 'utf-8';
+$conf['sql']['splitread'] = false;
+$conf['sql']['logqueries'] = false;
+$conf['sql']['phptype'] = 'pgsql';
+$conf['nosql']['phptype'] = false;
+$conf['ldap']['useldap'] = false;
+$conf['auth']['admins'] = array({{ glob_horde.admins | join(', ')}});
+$conf['auth']['checkip'] = false;
+$conf['auth']['checkbrowser'] = true;
+$conf['auth']['resetpassword'] = false;
+$conf['auth']['alternate_login'] = false;
+$conf['auth']['redirect_on_logout'] = false;
+$conf['auth']['list_users'] = 'list';
+$conf['auth']['params']['hostspec'] = '{{ glob_horde.imap }}';
+$conf['auth']['params']['port'] = 143;
+$conf['auth']['params']['secure'] = 'tls';
+$conf['auth']['driver'] = 'imap';
+$conf['auth']['params']['count_bad_logins'] = false;
+$conf['auth']['params']['login_block'] = false;
+$conf['auth']['params']['login_block_count'] = 5;
+$conf['auth']['params']['login_block_time'] = 5;
+$conf['signup']['allow'] = false;
+$conf['log']['priority'] = 'INFO';
+$conf['log']['ident'] = 'HORDE';
+$conf['log']['name'] = LOG_USER;
+$conf['log']['type'] = 'syslog';
+$conf['log']['enabled'] = true;
+$conf['log_accesskeys'] = false;
+$conf['prefs']['maxsize'] = 65535;
+$conf['prefs']['params']['driverconfig'] = 'horde';
+$conf['prefs']['driver'] = 'Sql';
+$conf['alarms']['params']['driverconfig'] = 'horde';
+$conf['alarms']['params']['ttl'] = 300;
+$conf['alarms']['driver'] = 'Sql';
+$conf['group']['params']['driverconfig'] = 'horde';
+$conf['group']['driver'] = 'Sql';
+$conf['perms']['driverconfig'] = 'horde';
+$conf['perms']['driver'] = 'Sql';
+$conf['share']['no_sharing'] = false;
+$conf['share']['auto_create'] = true;
+$conf['share']['world'] = true;
+$conf['share']['any_group'] = false;
+$conf['share']['hidden'] = false;
+$conf['share']['cache'] = false;
+$conf['share']['driver'] = 'Sqlng';
+$conf['cache']['default_lifetime'] = 86400;
+$conf['cache']['params']['sub'] = 0;
+$conf['cache']['driver'] = 'File';
+$conf['cache']['use_memorycache'] = '';
+$conf['cachecssparams']['url_version_param'] = true;
+$conf['cachecss'] = false;
+$conf['cachejsparams']['url_version_param'] = true;
+$conf['cachejs'] = false;
+$conf['cachethemes'] = false;
+$conf['lock']['params']['driverconfig'] = 'horde';
+$conf['lock']['driver'] = 'Sql';
+$conf['token']['params']['driverconfig'] = 'horde';
+$conf['token']['driver'] = 'Sql';
+$conf['history']['params']['driverconfig'] = 'horde';
+$conf['history']['driver'] = 'Sql';
+$conf['davstorage']['params']['driverconfig'] = 'horde';
+$conf['davstorage']['driver'] = 'Sql';
+$conf['mailer']['params']['sendmail_path'] = '/usr/lib/sendmail';
+$conf['mailer']['params']['sendmail_args'] = '-oi';
+$conf['mailer']['type'] = 'sendmail';
+$conf['vfs']['params']['driverconfig'] = 'horde';
+$conf['vfs']['type'] = 'Sql';
+$conf['sessionhandler']['type'] = 'Builtin';
+$conf['sessionhandler']['hashtable'] = false;
+$conf['spell']['driver'] = '';
+$conf['gnupg']['keyserver'] = array('pool.sks-keyservers.net');
+$conf['gnupg']['timeout'] = 10;
+$conf['nobase64_img'] = false;
+$conf['image']['driver'] = false;
+$conf['exif']['driver'] = 'Bundled';
+$conf['timezone']['location'] = 'ftp://ftp.iana.org/tz/tzdata-latest.tar.gz';
+$conf['problems']['email'] = 'webmaster@example.com';
+$conf['problems']['maildomain'] = 'example.com';
+$conf['problems']['tickets'] = false;
+$conf['problems']['attachments'] = true;
+$conf['menu']['links']['help'] = 'all';
+$conf['menu']['links']['prefs'] = 'authenticated';
+$conf['menu']['links']['problem'] = 'all';
+$conf['menu']['links']['login'] = 'all';
+$conf['menu']['links']['logout'] = 'authenticated';
+$conf['portal']['fixed_blocks'] = array();
+$conf['accounts']['driver'] = 'null';
+$conf['user']['verify_from_addr'] = false;
+$conf['user']['select_view'] = true;
+$conf['facebook']['enabled'] = false;
+$conf['twitter']['enabled'] = false;
+$conf['urlshortener'] = false;
+$conf['weather']['provider'] = false;
+$conf['imap']['enabled'] = false;
+$conf['imsp']['enabled'] = false;
+$conf['kolab']['enabled'] = false;
+$conf['hashtable']['driver'] = 'none';
+$conf['activesync']['enabled'] = false;
+/* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */
diff --git a/roles/horde/templates/horde/imp/backends.php.j2 b/roles/horde/templates/horde/imp/backends.php.j2
new file mode 100644
index 0000000000000000000000000000000000000000..b03fc3de616eed3e0405a5df8045f3194946a74e
--- /dev/null
+++ b/roles/horde/templates/horde/imp/backends.php.j2
@@ -0,0 +1,19 @@
+{{ ansible_header | comment(decoration='// ') }}
+<?php
+$servers['imp'] = array(
+    // Disabled by default
+    'disabled' => false,
+    'name' => 'IMAP Cr@ns',
+    'hostspec' => '{{ glob_horde.imap }}',
+    'hordeauth' => true,
+    'protocol' => 'imap',
+    'port' => 143,
+    'secure' => 'tls',
+    'maildomain' => '{{ glob_horde.maildomain }}',
+    'smtp' => array(
+        'host' => '{{ glob_horde.smtp }}',
+        'port' => 25,
+    ),
+    'cache' => false,
+);
+?>
diff --git a/roles/horde/templates/nginx/sites-available/horde.j2 b/roles/horde/templates/nginx/sites-available/horde.j2
new file mode 100644
index 0000000000000000000000000000000000000000..cbf84402e869e2fbd8675874a93210f358b04a34
--- /dev/null
+++ b/roles/horde/templates/nginx/sites-available/horde.j2
@@ -0,0 +1,17 @@
+{{ ansible_header | comment }}
+server {
+        listen {{ glob_horde.admin_src_hostname }}:80;
+        listen {{ loc_horde.ipv6 }}:80 ipv6only=on;
+        server_name {{ glob_horde.admin_src_hostname }} {{ glob_horde.src_hostname }};
+
+        root /usr/share/;
+        location / {
+            return 302 https://{{ glob_horde.dest_hostname }}/horde;
+        }
+        include "snippets/php.conf";
+
+        set_real_ip_from {{ glob_horde.zone_ipv4 }};
+        set_real_ip_from {{ glob_horde.zone_ipv6 }};
+        real_ip_header P-Real-Ip;
+}
+
diff --git a/roles/horde/templates/nginx/sites-available/webmail.j2 b/roles/horde/templates/nginx/sites-available/webmail.j2
new file mode 100644
index 0000000000000000000000000000000000000000..71270f89204cded39f28fc063634569e0b7949ef
--- /dev/null
+++ b/roles/horde/templates/nginx/sites-available/webmail.j2
@@ -0,0 +1,21 @@
+{{ ansible_header | comment }}
+server {
+        listen {{ glob_horde.admin_dest_hostname }}:80;
+        listen {{ loc_horde.ipv6 }}:80;
+        server_name {{ glob_horde.dest_hostname }} {{ glob_horde.admin_dest_hostname }};
+
+        root /usr/share/;
+        location / {
+            return 302 {{ glob_horde.redirection }};
+        }
+        location /horde {
+                try_files $uri $uri/ /horde/rampage.php?$args;
+                index index.php index.htm index.html;
+        }
+        include "snippets/php.conf";
+
+        set_real_ip_from {{ glob_horde.zone_ipv4 }};
+        set_real_ip_from {{ glob_horde.zone_ipv6 }};
+        real_ip_header P-Real-Ip;
+}
+
diff --git a/roles/horde/templates/nginx/snippets/php.conf.j2 b/roles/horde/templates/nginx/snippets/php.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..144ec4104779e1a7fd7be16b5cefb02c3b15a7c9
--- /dev/null
+++ b/roles/horde/templates/nginx/snippets/php.conf.j2
@@ -0,0 +1,26 @@
+{{ ansible_header | comment }}
+
+location ~ .+\.php {
+        fastcgi_split_path_info ^(.+\.php)(/.+)$;
+        if (!-e $document_root$fastcgi_script_name) {
+                return 404;
+        }
+        fastcgi_buffer_size   128k;
+        fastcgi_buffers   4 256k;
+        fastcgi_busy_buffers_size   256k;
+        fastcgi_pass   unix:/var/run/php/php7.3-fpm.sock;
+        fastcgi_index  index.php;
+        fastcgi_param  PATH_INFO          $fastcgi_path_info;
+        fastcgi_param  PATH_TRANSLATED    $document_root$fastcgi_path_info;
+        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
+        include fastcgi_params;
+}
+
+location ~ ^/php_(ping|status)$ {
+        access_log     off;
+        allow          127.0.0.1;
+        deny           all;
+        root           /usr/share/nginx/html;
+        fastcgi_pass   unix:/var/run/php/php7.3-fpm.sock;
+        include        fastcgi_params;
+}