Director
========

Director can be used by <Dovecot's IMAP/POP3/LMTP proxy>
[PasswordDatabase.ExtraFields.Proxy.txt] to keep a temporary user -> mail
server mapping. As long as user has simultaneous connections, the user is
always redirected to the same server. Each proxy server is running its own
director process, and the directors are communicating the state to each others.
Directors are mainly useful for setups where all of the mail storage is seen by
all servers, such as with NFS or a cluster filesystem.

First test non-director proxying
--------------------------------

The director is simply a small add-on for Dovecot proxy. Before configuring
director, you should test that a simple proxying setup with static destination
server works. See the <Proxy> [PasswordDatabase.ExtraFields.Proxy.txt] page for
more information about how to configure it. If you have a simple setup, you can
test this easily using a static passdb:

---%<-------------------------------------------------------------------------
passdb {
  driver = static
  args = proxy=y host=10.2.0.20 nopassword=y
}
---%<-------------------------------------------------------------------------

Once finished testing, remember to remove the "host" field.

Servers
-------

You need one or more servers assigned for Dovecot proxies. The same servers
could also act as backends handling the mails, but you need to run <two
separate Dovecot configurations> [RunningDovecot.txt] in different ports. This
may get a bit confusing, so it's not recommended (although v2.1 makes it easier
with 'instance_name' setting).

The directors are going to connect to each others in a ring. For example if you
have servers called A, B and C, director will create connections A->B, B->C and
C->A.

Director configuration
----------------------

In example configuration you can configure director from
'conf.d/10-director.conf'.

Listeners
---------

Configure the listeners that director requires:

---%<-------------------------------------------------------------------------
service director {
  unix_listener login/director {
    mode = 0666
  }
  fifo_listener login/proxy-notify {
    mode = 0600
    user = $default_login_user
  }
  # NOTE: director-userdb socket is actually used only for passdb lookups, not
userdb lookups
  unix_listener director-userdb {
    mode = 0600
  }
  inet_listener {
    port = 9090
  }
  ## uncomment this if you want to use
  ## doveadm director status -a ip:9091
  #inet_listener director-doveadm {
  #   port = 9091
  #}
}
---%<-------------------------------------------------------------------------

The port 9090 will be used for listening and connecting to other directors.
You're free to use any port number you want.

Configuring list of director servers
------------------------------------

List all of your directors in 'director_servers' setting separated by spaces.
You can use:

 * IP addresses
 * hostnames
 * hostnames that expand to multiple IPs (e.g. you could have a "directors-all"
   DNS entry that expands to all directors' IPs)

You can also add :port after the IP/host. The default port is the same as what
director service's inet_listener is using (the port 9090 above).

Note that the same director must not be listed multiple times with different
IPs. This especially means that a hostname can't expand to both IPv4 and IPv6
address. Otherwise Dovecot becomes confused about what directors actually
exist. This also means that a single director ring must use either IPv4 or IPv6
addresses, but not both at the same time.

For example if you have 3 directors, you could set:

---%<-------------------------------------------------------------------------
director_servers = 10.1.0.2 10.1.0.3 10.1.0.4
---%<-------------------------------------------------------------------------

Configuring list of mail servers
--------------------------------

List all of your backend mail servers in 'director_mail_servers' setting
separated by spaces. You can use:

 * IP addresses
 * IP ranges (e.g. 10.2.0.10-10.2.0.30)
 * hostnames
 * hostnames that expand to multiple IPs

For example if you had 20 mail servers with consecutive IPs:

---%<-------------------------------------------------------------------------
director_mail_servers = 10.2.0.11-10.2.0.30
---%<-------------------------------------------------------------------------

Enabling director
-----------------

Enable director for the wanted login services by telling them to connect to
director socket instead of the default login socket:

---%<-------------------------------------------------------------------------
service imap-login {
  executable = imap-login director
}
service pop3-login {
  executable = pop3-login director
}
---%<-------------------------------------------------------------------------

Consistent hashing should be enabled for new director clusters. It's not
possible to change this setting without a complete director cluster shutdown.
Using it reduces users being moved around when doing backend changes.

---%<-------------------------------------------------------------------------
director_consistent_hashing = yes # Supported by v2.2.16+
---%<-------------------------------------------------------------------------

If you want to enable director for LMTP, also set:

---%<-------------------------------------------------------------------------
# LMTP first does a passdb lookup to to see if there's a proxy field returned.
# If not, it fallbacks to doing userdb lookup.
lmtp_proxy = yes

protocol lmtp {
  # NOTE: director-userdb socket is actually used only for passdb lookups, not
userdb lookups
  auth_socket_path = director-userdb
}

# If you want lmtp-proxy listening on the network, uncomment the following:
#service lmtp {
#  inet_listener lmtp {
#    port = 24
#  }
#}
---%<-------------------------------------------------------------------------

By default LMTP proxy connects to the same port in backend as what was used for
the incoming connection.

Other settings
--------------

Directors redirect a user to the same server always the user has active
connections. The redirection is also done for a while after the last connection
already disconnected. This is mainly to avoid trouble with NFS caches that
haven't yet expired. You can configure this setting from:

---%<-------------------------------------------------------------------------
director_user_expire = 15 min
---%<-------------------------------------------------------------------------

'doveadm director kick' and 'doveadm director move' need to be able to connect
to the 'ipc' socket. Make sure the director process can do it:

---%<-------------------------------------------------------------------------
service ipc {
  unix_listener ipc {
    user = dovecot # This is already the default in v2.3.1+
  }
}
---%<-------------------------------------------------------------------------

Passdb configuration
--------------------

Your passdb must return "proxy" <extra field>
[PasswordDatabase.ExtraFields.txt], otherwise director doesn't do anything.

Director works by adding a "host" extra field to the auth reply, which contains
the temporary destination mail server. This "host" field isn't added if the
passdb lookup already returns "host". This allows configuring some users to be
always proxied to a specific server.

If the backend servers verify password, you can use static passdb for director:

---%<-------------------------------------------------------------------------
passdb {
  driver = static
  args = proxy=y nopassword=y
}
---%<-------------------------------------------------------------------------

Note that while this is the simplest director configuration, users will be
assigned to a backend before they have been authenticated.  A director
configured this way can be attacked by sending it a large number of unknown
users.  To prevent this, the director should be configured to authenticate the
user and might make use of a master password to log into the backend servers.

Doveadm server
--------------

Use these settings for both director and backends:

---%<-------------------------------------------------------------------------
service doveadm {
  inet_listener {
    # any port you want to use for this:
    port = 24245
  }
}

local 10.10.10.0/24 {
  # password to use for client authentication
  doveadm_password = secret
  # allow client to only use specified list of commands (default is all):
  #doveadm_allowed_commands =
}
---%<-------------------------------------------------------------------------

The director also needs the following configuration:

---%<-------------------------------------------------------------------------
# same port as doveadm's inet_listener
doveadm_proxy_port = 24245

protocol doveadm {
  # NOTE: director-userdb socket is actually used only for passdb lookups, not
userdb lookups
  auth_socket_path = director-userdb
}
---%<-------------------------------------------------------------------------

Now you can run doveadm commands on the director, and it'll run them
automatically on the correct backend server.

Health monitoring of backend servers
------------------------------------

Brad Davidson has written a small daemon for monitoring backend servers, and
disable/enable them on demand.
Ref:https://dovecot.org/list/dovecot/2010-August/051946.html

Forcefully moving users to a different backend
----------------------------------------------

This is useful if you need to do maintenance on one of the backend servers and
want (active) clients to move to a different backend:

 1. Disable any watchdog system that will undo changes you make to backend
    server weights, such as poolmon.
     * Not needed if the watchdog is new enough to use HOST-UP/HOST-DOWN
       commands rather than change weights.
 2. Set the weight of the backend server to be worked on to 0: 'doveadm
    director add <backend server ip> 0'
 3. Flush current assignments to disable new connections to this backend:
    'doveadm director flush <backend server ip>'
     * This will also kick the existing connections to the backend in v2.2.19+.

Most IMAP clients will silently just reconnect to the (new backend) server
after being kicked (at least Apple Mail 6.0 and Thunderbird 14.0).

For moving specific users to other servers (e.g. because there are too many
"heavy users" assigned to the same backend), you can use 'doveadm director
move' command in v2.0.14+. This requires the ipc permissions to be configured
correctly (see above).

Tags
----

(Requires v2.2.16+)

*WARNING*: This feature isn't working perfectly in v2.2.26.1 and older. If two
users with different tags have the same 32bit hash, they may end up going to
the wrong tag's backend.

With tags you can use a single director ring to serve multiple backend
clusters. Each backend cluster is assigned a tag name, which can be anything
you want. By default everything has an empty tag. A passdb lookup can return
"director_tag" field containing the wanted tag name. If there aren't any
backend servers with the wanted tag, it's treated the same as if there aren't
any backend servers available (= wait for 30 secs for a backend and then return
temporary failure).

Tags can be added to configuration by adding @tag suffix to IPs/hosts. For
example:

---%<-------------------------------------------------------------------------
director_mail_servers = 10.0.0.100-10.0.0.110@name1 10.0.0.120@name2
---%<-------------------------------------------------------------------------

"doveadm director add" can also add tags either with @tag suffix or with -t
parameter. "doveadm director status user@domain" requires giving the user's
correct tag with -t parameter or the results won't be correct (empty tag's
results are shown). Tags can't currently be changed for an existing host
without removing it first.

Director and Backend in same server (broken)
--------------------------------------------

NOTE: This feature never actually worked. It would require further development
to fix (director would need to add "proxy" field to extra fields and notify
auth that the auth_request can be freed).

Have the passdb lookup return 'director_proxy_maybe=y'. LMTP however doesn't
currently support mixing recipients to both being proxied and store locally.

Flush socket
------------

(Requires v2.2.26+)

This allows calling a script for each user (hash) that is moved between
backends. This is triggered by "doveadm director move" and "doveadm director
flush" commands. What happens is:

 * User's connections are kicked from the director cluster
 * Flush socket is called and waited on.
 * User logins are delayed until the flush socket is finished, or the user move
   times out after 30 seconds (hardcoded).
 * Only the director that initiated the doveadm command will call the flush
   socket.
    * director_user_kick_delay is ignored by the initiating director, but used
      by the other directors.

Configuration:

---%<-------------------------------------------------------------------------
director_flush_script = user-flush
service user-flush {
  executable = script /usr/local/bin/user-flush.sh
  unix_listener user-flush {
    user = dovecot
  }
}
---%<-------------------------------------------------------------------------

The user-flush.sh will receive as parameters:

 * "FLUSH"
 * username hash
 * old host's IP
 * new host's IP

(This file was created from the wiki on 2019-06-19 12:42)
