Nginx può essere impiegato come proxy server per i protocolli IMAP, POP3 e SMTP, rendendolo di fatto un Mail Proxy Server. L'impiego di un unico endpoint pubblico per l'accesso ai servizi di posta permette di distribuire il carico su più server di backend e di implementare politiche avanzate di selezione del server (ad esempio, basate su geolocalizzazione IP).
Configurazione
I parametri di configurazione del mail proxy server sono inclusi nel contesto mail. La prima direttiva da inserire nel blocco mail
serve ad indicare il nome FQDN del server e si chiama appunto server_name. Ad esempio:
mail {
server_name mail.example.com;
#...
}
Estensioni dei protocolli
Nginx permette di configurare le opzioni supportate dai protocolli in ingresso. Ad esempio, con la direttiva imap_capabilities è possibile specificare le estensioni IMAP che il server accetterà. Una lista completa delle capabilities del protocollo IMAP è disponibile su iana.org.
In uno scenario tipico, questa direttiva verrà configurata per indicare le stesse capabilities supportate dai server IMAP di backend. Ad esempio, con la configurazione seguente verranno abilitate le estensioni IMAP4rev1 e UIDPLUS:
mail {
server_name mail.example.com;
imap_capabilities "IMAP4rev1" "UIDPLUS";
#...
}
Analogamente, è possibile specificare le estensioni da attivare per il protocollo POP3 con la direttiva pop3_capabilities. Ad esempio, la configurazione seguente attiverà le estensioni TOP e USER:
mail {
server_name mail.example.com;
pop3_capabilities "TOP" "USER";
#...
}
Autenticazione
L'aspetto più importante nella configurazione di Nginx come mail proxy server è dato dalla particolare modalità di autenticazione implementata. A differenza delle modalità di load balancing di livello 7 o di livello 4, illustrate nelle lezioni precedenti (rispettivamente qui e qui), la selezione del server di backend non è effettuata direttamente da Nginx ma viene affidata ad un servizio terzo.
In particolare, Nginx richiede l'implementazione di un servizio HTTP che si farà carico di validare le credenziali degli utenti e di selezionare il server di backend adeguato. Per grandi linee, il processo di autenticazione si articola nelle fasi elencate di seguito:
- Il client si connette al server Nginx ed inizia la fase di autenticazione secondo il protocollo in uso (ad esempio, con SMTP invierà un messaggio AUTH);
- Il server Nginx contatta il servizio HTTP di autenticazione, inviando le credenziali ricevute dal client direttamente via HTTP (metodo di autenticazione HTTP Basic;
-
Il servizio HTTP verifica le credenziali secondo un'opportuna logica e nel caso in cui esse sian valide restituisce una risposta HTTP contenente tre header HTTP speciali:
- Auth-Status, che indica che l'autenticazione è andata a buon fine;
- Auth-Server, che riporta l'indirizzo IP del server di backend che Nginx dovrà utilizzare;
- Auth-Port, che indica il numero di porta al quale contattare il server di backend;
Nel caso in cui le credenziali non siano valide, il servizio HTTP risponderà senza i tre header indicati sopra;
- Ottenuta una risposta dal servizio HTTP, Nginx provvede a contattare il server di backend indicato. Nel caso di IMAP e POP3, Nginx invierà nuovamente le credenziali al server di backend, dato che il processo di autenticazione è necessario per individuare univocamente le risorse alle quali accedere. In altre parole, quando si accede ad un server IMAP o POP3, è necessario autenticarsi per indicare a quale casella di posta si vuole accedere. Nel caso di SMTP invece, Nginx non invierà alcun messaggio di autenticazione, anche se questo è stato precedentemente inoltrato dal client.
Il blocco mail
va quindi configurato opportunamente in modo da specificare il servizio HTTP di autenticazione da utilizzare. Ciò viene fatto utilizzando la direttiva auth_http. Ad esempio, supponendo che il servizio HTTP risponda all'URL http://localhost:9000/mail/auth.php, dovremo specificare:
mail {
server_name mail.example.com;
auth_http localhost:9000/mail/auth.php;
#...
}
Il servizio HTTP di autenticazione può essere implementato in qualunque linguaggio e contenere logiche di autenticazione piuttosto articolate. In casi più semplici, è sufficiente uno script PHP, che può essere servito dalla stessa istanza di Nginx.
Una semplice implementazione del servizio di autenticazione, basata sugli esempi disponibili nella documentazione ufficiale (disponibile qui), è riportata di seguito:
<?php
/*
Il server Nginx richiama questo script inviando le seguenti variaibli:
HTTP_AUTH_USER = nome utente
HTTP_AUTH_PASS = password
HTTP_AUTH_PROTOCOL = protocollo (può essere "imap", "smtp" o "pop3")
*/
if (!isset($_SERVER["HTTP_AUTH_USER"] ) || !isset($_SERVER["HTTP_AUTH_PASS"] )){
fail();
}
$username=$_SERVER["HTTP_AUTH_USER"] ;
$userpass=$_SERVER["HTTP_AUTH_PASS"] ;
$protocol=$_SERVER["HTTP_AUTH_PROTOCOL"] ;
// porta TCP da utilizzare, in base al protocollo richiesto
$backend_port=110;
if ($protocol=="imap") {
$backend_port=143;
}
if ($protocol=="smtp") {
$backend_port=25;
}
// Lista dei server di backend e dei relativi indirizzi IP
// application gives back hostname, convert it to ip address here
$backend_ip["mailhost01"] ="192.168.1.22";
$backend_ip["mailhost02"] ="192.168.1.33";
// Verifica le credenziali dell'utente
if (!authuser($username,$userpass)){
fail();
exit;
}
// Get the server for this user if we have reached so far
$server_ip=getmailserver($username);
// Restituisce gli header richiesti da Nginx
pass($server_ip, $backend_port);
//END
function authuser($user,$pass){
// caratteri speciali convertiti da Nginx:
// " " 0x20h (SPACE)
// "%" 0x25h
$pass = str_replace('%20',' ', $pass);
$pass = str_replace('%25','%', $pass);
// INSERIRE QUI LA LOGICA DI AUTENTICAZIONE.
// Questa funzione restituisce true nel caso in cui le credenziali siano valide.
return true;
}
function getmailserver($user){
// questa funzione viene utilizzata per determinare il server di backend.
// Ad esempio, usa mailhost01 per tutti gli utenti il cui nome contiene
// "@host.com", e mailhost02 per tutti gli altri.
if (strpos($username, '@host.com') !== false) {
return $backend_ip["mailhost01"];
} else {
return $backend_ip["mailhost02"];
}
}
function fail(){
header("Auth-Status: Invalid login or password");
exit;
}
function pass($server,$port){
header("Auth-Status: OK");
header("Auth-Server: $server");
header("Auth-Port: $port");
exit;
}
?>
Specifica dei protocolli
Nel blocco mail
verranno inoltre indicati esplicitamente i protocolli da utilizzare, mediante il blocco server. Il blocco server
indica il numero di porta TCP da usare, il protocollo ed i metodi di autenticazione. Ad esempio, nel caso in cui si vogliano attivare tutti i protocolli supportati (IMAP, POP3, SMTP), bisognerà specificare tre blocchi server
, come nell'esempio seguente:
mail {
server_name mail.example.com;
#...
server {
listen 25;
protocol smtp;
smtp_auth login plain cram-md5;
}
server {
listen 110;
protocol pop3;
pop3_auth plain apop cram-md5;
}
server {
listen 143;
protocol imap;
}
}
SSL/TLS
Come è noto, i protocolli IMAP, POP3 ed SMTP possono essere affiancati da SSL/TLS. Per attivare queste opzioni è sufficiente specificare nel blocco mail
il percorso del certificato e della relativa chiave privata, elencare i protocolli supportati ed i relativi cifrari e, ovviamente, abilitare il modulo ssl. Ad esempio, una tipica configurazione SSL potrebbe essere la seguente:
mail {
server_name mail.example.com;
#...
ssl on;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/certs/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
}
Nel caso in cui si voglia utilizzare STARTTLS (per IMAP ed SMTP) e STLS (per POP3) al posto di SSL/TLS, bisognerà specificare la direttiva starttls al posto di ssl:
mail {
server_name mail.example.com;
#...
starttls on;
#...
}