lunes, 11 de abril de 2011

Cache Multisite


La finalidad de este howto es la dotar a nuestros sites de un sistema de caches para ahorrar ancho de banda en origen, aumentar el rendimiento de los sites y protegernos de posibles fallas en los servidores origen, para ello vamos a utilizar varnish para todo el tema de cacheo de estaticos y nginx para gestionar el tema de multisite de una manera más sencilla y eficiente de la que podriamos hacerlo con varnish.
El punto de entrada de la solución es varnish quien atiende al puerto 80 como si del servidor principal se tratara. En el puerto 81 estará corriendo nginx quien redireccionará todas las request que varnish no tenga en cache al servidor origen correcto, mediante proxy_pass.
Primero el fichero de configuración de varnish.
# Backends
backend default {
  .host = "127.0.0.1";
  .port = "81";
}
# ACL Purge
acl limpia {
      "localhost";
      "10.90.90.0"/24;
      "10.90.40.0"/24;
      "10.90.55.0"/24;
} 
sub vcl_recv {
   # Metemos el X-Forwarder-for
   set req.http.X-Forwarded-For = client.ip;
   # Si el backend tarda mucho en generar la pagina sirve el objeto expirado.
   set req.grace = 2m;
   # Si el metodo no es el esperado no lo permitimos
   if (req.request != "GET" &&
     req.request != "HEAD" &&
     req.request != "POST" &&
     req.request != "PURGE") {
error 405 "Method Not Allowed";
   }
   # Dejamos pasar el POST sin cachear
   if (req.request == "POST") {
       return (pass);
   }
  # Filtro de purgado
  if (req.request == "PURGE") {
      if (!client.ip ~ limpia) {
          error 405 "Method Not Allowed";
      }
      return(lookup);
  }
   # La autenticacion la dejamos pasar hasta el backend sin cachear
   if (req.http.Authorization) {
       /* Not cacheable by default */
       return (pass);
   }
  # Si la peticion tiene cookie la cacheamos igualmente.
  if (req.request == "GET" && req.http.cookie) {
    return(lookup);
  }
   return (lookup);
}
sub vcl_hit {
   if (!obj.cacheable) {
       return (pass);
   }
   if (req.request == "PURGE") {
      set obj.ttl = 0s;
      error 200 "Purged.";
  }
   return (deliver);
}
sub vcl_hash {
      if (req.http.Accept-Encoding ~ "gzip") {
              set req.hash += "gzip";
      }
      else if (req.http.Accept-Encoding ~ "deflate") {
              set req.hash += "deflate";
      }
}
sub vcl_miss {
  if (req.request == "PURGE") {
 error 404 "Not in cache.";
  }
}
sub vcl_fetch {
   # Si el backend tarda mucho en generar la pagina sirve el objeto expirado.
   set beresp.grace = 2m; 
   if (beresp.http.Set-Cookie) {
       return (deliver);
   }
  # No cachear si tenemos autorizacion
  if (req.http.Authorization) {
      return(pass);
  }
  # No cachear si lo dice cache-control
  if( beresp.http.Pragma ~ "no-cache" ||
      beresp.http.Cache-Control ~ "no-cache" ||
      beresp.http.Cache-Control ~ "private" ||
      beresp.http.Cache-Control ~ "max-age=0" ||
      beresp.http.Cache-Control ~ "must-revalidate" ||
      beresp.http.Cache-Control ~ "no-store" ||
      beresp.http.Cache-Control ~ "private" ) {
      return(pass);
  }
   return (deliver);
}
sub vcl_deliver {
   if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
   } else {
        set resp.http.X-Cache = "MISS";
   }
   return (deliver);
}
sub vcl_error {
   set obj.http.Content-Type = "text/html; charset=utf-8";
   synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
 <head>
   <title>"} obj.status " " obj.response {"</title>
 </head>
 <body>
   <h1>Error "} obj.status " " obj.response {"</h1>
   <p>"} obj.response {"</p>
   <h3>Guru Meditation:</h3>
   <p>XID: "} req.xid {"</p>
   <hr>
   <p>Varnish cache server</p>
 </body>
</html>
"};
   return (deliver);
}
Como se ve en las primeras lineas del fichero de configuración defaul.vcl estamos poniendo como backend el nginx que corre en el puerto 81.
Ahora el fichero de configuración del nginx:
 
user  nobody nogroup;
worker_processes  1;
error_log  logs/error.log;
events {
  worker_connections  1024;
}
http {
  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  keepalive_timeout  65;
  upstream origen1 {
      server origen.prueba.com:80; 
  }
  upstream origen2 {
      server origen2.example.com:80; 
  }
  server {
      listen       81;
      server_name  www.prueba.com;
      location / {
              proxy_set_header  X-Real-IP  $remote_addr;
              proxy_set_header Host $http_host;
              proxy_pass http://origen1;
      }
  }
  server {
      listen       81;
      server_name  www.example.com;
      location / {
              proxy_set_header  X-Real-IP  $remote_addr;
              proxy_set_header Host $http_host;
              proxy_pass http://origen2;
      }
  }
}
En la configuración del nginx estamos definiendo varios servidores origen en funcion de la request que le esté pasando el varnish.

Por último solo nos queda probar que todo funciona como debe.

miércoles, 6 de abril de 2011

Controlar la actividad de los usuarios con snoopy

A todo Administrador, alguna vez le ha surgido la necesidad de saber quien ha borrado el fichero de turno, si hay algún usuario más listo de la cuenta o por que no, por que mola saberlo.

Pues bien, mediante esta fácil solución podemos conocer los comandos que ha ejecutado un usuario en todo momento.

Para ello necesitamos instalar la librería de snoopy.
apt-get install snoopy
Cuando instalas por defecto te mete en /etc/ld.so.preload la linea /lib/snoopy.so, debemos comentarla si no queremos que nuestro sistema este logando sin parar la actividad de todos los usuarios del sistema y cuando digo todos, digo todos, daemon, www-data, tomcat, etc (que en algún caso también podría resultarnos de gran utilidad, pero no es el caso).
Una vez en este punto creamos el script /bin/snoopy_bash con el siguiente contenido y le damos permisos de ejecución (755):
#!/bin/bash
# Bash que loga la actividad de los usuario
export LD_PRELOAD=/lib/snoopy.so
/bin/bash
 
 
 
chmod 755 /bin/snoopy_bash
Solo nos queda cambiar el bash por defecto que use el usuario que queremos controlar en el fichero /etc/passwd y ver como todos los comandos que este usuario ejecuta se van quedando en el /var/log/auth.log
pruebas:x:1012:1002::/home/pruebas:/bin/snoopy_bash

domingo, 27 de febrero de 2011

Autenticar Apache contra ldap

1. Tenemos que compilar apache con las siguientes opciones en el configure:
  1. --enable-authnz-ldap
  2. --with-ldap
  3. --enable-ldap
2. Una vez compilado el apache, creamos un usuario y un grupo en el directorio ldap: (el campo gidNumber, home y uidNumber varian de un usuario a otro)

##### Usuario ########
dn: cn=jroman,ou=Usuarios,dc=casa,dc=loc
cn: jroman
sn: Roman
uid: jroman
userPassword: {MD5}/gz+58AqfPH5ekA==
objectClass: inetOrgPerson
objectClass: shadowAccount
objectClass: top
objectClass: posixAccount
gidNumber: 10000
homeDirectory: /home/jroman
uidNumber: 10000


###### Grupo ########
dn: cn=Manager,ou=Grupos,dc=casa,dc=loc
cn: Manager
gidNumber: 10000
objectClass: posixGroup
objectClass: top



3. Ahora vamos a crear un site al cual vamos a acceder autenticando contra el ldap. La autenticacion se va a hacer por grupo, es decir van a poder entrar al site todos los usuarios que tengan como grupo el elegido por el site. Aqui vamos a usar el atributo ldap-attribute.

######## Alias documentacion O'Reilly #######
  Alias /libreria "/DATA/proyects/libreria"
  <Directory "/DATA/proyects/libreria">
    Options -Indexes MultiViews FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
    AuthType Basic
    AuthName "Secure Area"
    AuthBasicProvider "ldap"
    AuthzLDAPAuthoritative   Off
    AuthLDAPURL "ldap://localhost:389/ou=Usuarios,dc=casa,dc=loc?uid"
    Require ldap-attribute gidNumber=10000
  </Directory>



4. Ahora autenticamos por la pertenencia a una Unidad Organizativa.
 
######## Alias documentacion O'Reilly #######
 Alias /libreria "/DATA/proyects/libreria"
 <Directory "/DATA/proyects/libreria">
    Options -Indexes MultiViews FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
    AuthType Basic
    AuthName "Secure Area"
    AuthBasicProvider "ldap"
    AuthzLDAPAuthoritative   Off
    AuthLDAPURL "ldap://localhost:389/ou=Usuarios,dc=casa,dc=loc?uid"
    Require valid-user
 </Directory>





 5. Si lo que queremos es autenticar por pertenencia a un grupo determinado, creamos un grupo que tenga el objectclass groupOfUniqueNames:
 
dn: cn=web,ou=Grupos,dc=casa,dc=loc
objectClass: groupOfUniqueNames
uniqueMember: cn=jroman,ou=Usuarios,dc=casa,dc=loc
uniqueMember: cn=admin,ou=Usuarios,dc=casa,dc=loc

Ahora le decimos al apache que autentique contra ldap y busque los usuario que pertenecen al grupo web:
####### Alias proxy #######
  Alias /proxy "/DATA/proyects/proxy"
  <Directory "/DATA/proyects/proxy">
    Options Indexes MultiViews FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
    AuthType Basic
    AuthName "Secure Area"
    AuthBasicProvider "ldap"
    AuthzLDAPAuthoritative   Off
    AuthLDAPURL "ldap://localhost:389/dc=casa,dc=loc?uid"
    Require ldap-group cn=web,ou=Grupos,dc=casa,dc=loc
 </Directory>
############################################

viernes, 11 de febrero de 2011

OpenVPN con certificados

Introducción

Para crear las vpn de cliente, necesitamos tener una entidad certificadora para generar los certificados de cliente y servidor, que en nuestro caso estará en Server1 y el software openvpn instalado en las máquinas. Los certificados para la vpn  estarán en /opt/certificados/keys.
Para las vpn de los clientes generaremos un certificado por cada uno de ellos, debido a que necesitamos poder asignar IPs fijas a cada cliente, y esto se consigue mediante un certificado único por cliente.

Creación de la entidad cerificadora

  1. Para la creación de la entidad certificadora, en el directorio /opt/certificados  de la máquina que hara las veces de CA, copiamos el contenido de /usr/share/doc/openvpn/examples/easy-rsa/ a /opt/certificados.
  2. El siguiente paso es modificar el fichero vars con los datos correspondientes.
         export KEY_COUNTRY=es
         export KEY_PROVINCE=Madrid
         export KEY_CITY=Madrid
         export KEY_ORG="Miempresa"
         export KEY_EMAIL="sistemas@miempresa.com"
  1. Cargamos las variables de entorno, lanzamos la limpieza de certificados y generamos la CA.
         . ./vars
         ./clean-all
         ./build-ca

Generación de certificados y clave para el servidor

  • Para la generación del certificado de servidor hay que lanzar el siguiente comando:
         ./build-key-server server

Generación de certificados de cliente

  • En el caso de las vpn de los clientes tenemos que repetir este proceso por cada cliente, por que como hemos comentado arriba, las servoapp necesitan de una IP fija para su monitorización y el proceso de recuperación de datos del cliente.
          ./build-key cliente1
          root@baco /opt/certificados $ ./build-key cliente1
          Generating a 1024 bit RSA private key
          ......................++++++
          ..........................................................++++++
          writing new private key to 'cliente1.key'
          -----
         You are about to be asked to enter information that will be incorporated
         into your certificate request.
         What you are about to enter is what is called a Distinguished Name or a DN.
         There are quite a few fields but you can leave some blank
         For some fields there will be a default value,
         If you enter '.', the field will be left blank.
         -----
         Country Name (2 letter code) [es]:
         State or Province Name (full name) [Madrid]:
         Locality Name (eg, city) [Madrid]:
         Organization Name (eg, company) [Miempresa Cliente]:
         Organizational Unit Name (eg, section) []:sistemas
         Common Name (eg, your name or your server's hostname) []:cliente1
         Email Address [sistemas@miempresa.com]:
         Please enter the following 'extra' attributes
         to be sent with your certificate request
         A challenge password []:
         An optional company name []:
         Using configuration from /opt/certificados/openssl.cnf
         Check that the request matches the signature
         Signature ok
         The Subject's Distinguished Name is as follows
         countryName           :PRINTABLE:'es'
         stateOrProvinceName   :PRINTABLE:'Madrid'
         localityName          :PRINTABLE:'Madrid'
         organizationName      :PRINTABLE:'Miempresa Cliente'
         organizationalUnitName:PRINTABLE:'sistemas'
         **commonName            :PRINTABLE:'cliente1'**
         emailAddress          :IA5STRING:'sistemas@miempresa.com'
         Certificate is to be certified until Dec  6 11:27:35 2017 GMT (3650 days)
         Sign the certificate? [y/n]:y
         1 out of 1 certificate requests certified, commit? [y/n]y
         Write out database with 1 new entries
         Data Base Updated
  • Es muy importante a la hora de generar el certificado de cliente el campo commonName ya que deberemos crear un fichero con ese mismo nombre dentro de /etc/openvpn/ccd para que openvpn asigne una IP fija a ese cliente.

Generación Diffie Hellman

         ./build-dh

Fichero de configuración

Un vez generados los certificados y la CA (/opt/certificados/keys), debemos copiar al directorio /etc/openvpn/ del servidor, los siguientes ficheros:
  • ca.crt
  • server.crt
  • server.key
  • dh1024.pem
Ahora vamos a pasar el fichero de configuración server.conf:
         port 1194
         proto tcp
         dev tun
         ca server/ca.crt
         cert server/server.crt
         key server/server.key  
         dh server/dh1024.pem
         server 10.0.0.0 255.255.255.0
         ifconfig-pool-persist ipp.txt
         client-config-dir ccd
         keepalive 10 120
         comp-lzo
         user nobody
         group nogroup
         persist-key
         persist-tun
         status openvpn-status.log
         verb 3
  • En la directiva “client-config-dir ccd” espeficicamos a openvpn que lea cualquier fichero contenido en este directorio que coincida con el commonName del certificado de cliente. Por ejemplo, hemos creado un fichero llamado cliente1 que contiene la linea:
         ifconfig-push 10.0.0.250 10.0.0.1
De esta manera le decimos a openvpn que reserve esta IP para el certificado de cliente cliente1, siendo 10.0.0.250 la IP asignada al cliente y 10.0.0.1 la IP que tiene el servidor.
Para la configuración de la vpn del lado del cliente , necesitaremos enviar los ficheros:
  • ca.crt
  • cliente1.crt
  • cliente1.key
Así mismo el fichero de configuración del lado del cliente tendrá el siguiente contenido
         client
         dev tun
         proto tcp
         remote 80.25.33.194 1194
         resolv-retry infinite
         nobind
         persist-key
         persist-tun
         ca servotic_cliente/ca.crt
         cert servotic_cliente/cliente1.crt
         key servotic_cliente/cliente1.key
         comp-lzo
         verb 3

martes, 8 de febrero de 2011

Shellinabox. SSH via web

Introducción

A quien no le ha pasado el necesitar en un momento dado acceder por ssh a su servidor pero el puerto 22 esta cerrado...esta es la solución, ShellinaBox es una herramienta que sirve para poder acceder via web a la consola del equipo que lo ejecuta. También con la configuración adecuada puedes hacer que el equipo que ejecuta la herramienta sirva de pasarela ssh para otras máquinas.
http://code.google.com/p/shellinabox/

Instalación
La instalación es muy sencilla.
# wget http://code.google.com/p/shellinabox/downloads/detail?name=shellinabox-2.10.tar.gz&can=2&q=
# tar zxvf shellinabox-2.10.tar.gz
# cd shellinabox-2.10
# .configure --prefix=/opt/shellinabox
# make && make install

Script de arranque
Este es el script de arranque que levanta el demonio en el puerto 4200 de localhost.
#!/bin/bash
case $1 in
      start)
              echo "Arrancando ShellInABox"
              /opt/shellinabox/bin/shellinaboxd -b -t -s /:LOGIN
      ;;
      stop)
              echo "Parando ShellInABox"
              pkill -f shellinaboxd
      ;;
      *)
              echo "$0 [stop|start]"
      ;;
esac

Apache
Para poder acceder desde fuera hacemos un proxypass desde un virtual que sea accesible desde fuera:
      ProxyRequests Off
     <Proxy *>
             Order deny,allow
             Allow from all
             AuthType Basic
             AuthName "Consola"
             AuthUserFile /opt/apache/conf/console.pwd
             Require valid-user
     </Proxy>
     ProxyPass /console/ http://localhost:4200
     ProxyPassReverse /console/ http://localhost:4200/


Puesta en Marcha
Ya lo tenemos listo, arrancamos shellinabox (/etc/init.d/console start) y reinicaimos apache. Ahora solo queda probar:

domingo, 6 de febrero de 2011

Crear un volumen RAM para tablas temporales


Cuando tenemos problemas de acceso a disco y nos encontramos con que en el processlist vemos muchas query con el estado “Copy to tmp table”, si disponemos de suficiente RAM podemos montar una particion RAM para que se escriban ahi las tablas temporales.
mount tmpfs /tmpfs -t tmpfs
En el /etc/fstab:
mpfs           /tmpfs          tmpfs   rw 0 0
Por último en el my.cnf:
tmpdir = /tmpfs

Replicación Mysql Master-Master

Introducción

El objetivo es montar una replicación nativa de mysql en modo master-master mediante la herramienta mmm (Mysql MultiMaster). Es este caso vamos a usar dos servidores mysql5.1 sin datos (salvo las db de test y mysql).
Para el correcto funcionamiento del cluster el demonio mmm_monitor encargado de gestionar los roles del cluster lo vamos a sacar a otra máquina. (Tambien podriamos montarlo en el nodo pasivo).

Requisitos previos:

Los datafiles deben de ir en un volumen LVM para aprovecharnos de la posibilidad de hacer el mmm_clone para restore de datos. Por ejemplo para el ejemplo hemos creado un volumen LVM de 4 GB montado en el /DATABASE (los datafile estan dentro de /DATABASE/data).
Es importante dejar espacio sin asignar en LVM para realizar los snapshots.
Para nuestra configuración vamos a necesitar 4 ips:
  1. mmm1 (ip para la máquina física).
  2. mmm2 (ip para la máquina física).
  3. rol writer.
  4. rol reader (para un cluster activo-pasivo no es necesario, pero si queremos separar las lecturas de las excrituras si).

Configuración del mysql y la replicación.

Compilar un mysql de manera standard(o descargar los binarios).
Modificar el /etc/my.cnf
log-bin=mysql-bin
binlog_format=mixed
server-id = 10
read-only = 1
max_binlog_size                 = 100M
max_relay_log_size              = 100M
Creamos el usuario de replicaron en ambas maquinas.
mysql> GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%' 
IDENTIFIED BY 'replicator'; 
Migramos los datos. Si están vacíos los mysql no hace falta.
Configuramos la replicacion:
mmm1 mysql>CHANGE MASTER TO MASTER_HOST='mmm2', 
MASTER_USER='replicator', MASTER_PASSWORD='replicator', 
MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=380;
mmm2 mysql>CHANGE MASTER TO MASTER_HOST='mmm1', 
MASTER_USER='replicator', MASTER_PASSWORD='replicator', 
MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=512; 
El valor de los campos MASTER_LOG_POS y MASTER_LOG_FILE lo sacamos ejecutando el comando SHOW MASTER STATUS en cada nodo.
Activamos la replicaición:
mysql> START SLAVE; 

Configuración mmm

Crear los usuarios que necesita el mmm:
- monitor user
- agent user
- replication user
GRANT REPLICATION CLIENT ON *.* TO 'mmm_monitor'@'192.168.1.%' 
IDENTIFIED BY 'mmm_monitor';
GRANT SUPER, REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'192.168.1.%' 
IDENTIFIED BY 'mmm_agent';
GRANT REPLICATION SLAVE ON *.* TO 'mmm_replication'@'192.168.1.%' 
IDENTIFIED BY 'mmm_replication';
GRANT SUPER, REPLICATION CLIENT, RELOAD ON *.* TO 'mmm_tools'@'192.168.1.%'
 IDENTIFIED BY 'mmm_tools'; 
Creamos el usuario “mmmd”
useradd --comment "MMM Script Owner" --shell /sbin/nologin mmmd 
Configuramos las mmm_tools:
mkdir /mmm_snapshot /mmm_backup /DATABASE/data/_mmm 

Ficheros de configuración

  • /etc/mysql-mmm/mmm_agent.conf (personalizar por cada nodo)
include mmm_common.conf
this mmm1
  • /etc/mysql-mmm/mmm_common.conf (este fichero es comun a todos los nodos incluido el monitor)
active_master_role      writer
<host default>
      cluster_interface               eth0
      pid_path                                /var/run/mmm_agentd.pid
      bin_path                                /usr/lib/mysql-mmm/
      replication_user        mmm_replication
      replication_password    mmm_replication
      agent_user                              mmm_agent
      agent_password                  RepAgent
</host>
<host mmm1>
      ip                                              192.168.1.242
      mode                                    master
      peer                                    mmm2
</host>
<host mmm2>
      ip                                              192.168.1.243
      mode                                    master
      peer                                    mmm1
</host>
<role writer>
      hosts                                   mmm1, mmm2
      ips                                     192.168.1.244
      mode                                    exclusive
      prefer                                  mmm1
</role>
<role reader>
      hosts                                   mmm1, mmm2
      ips                                     192.168.1.245
      mode                                    balanced
</role>
  • /etc/mysql-mmm/mmm_tools.conf (común a todos los nodos)
include mmm_agent.conf
default_copy_method                     scp
clone_dirs                                      data
<host default>
      ssh_user                                root
lvm_snapshot_size           1G
      lvm_logical_volume          database
      lvm_volume_group            vol0
      lvm_mount_dir                       /mmm_snapshot
      lvm_mount_opts                      -orw
      tools_user                              mmm_tools
      tools_password                          mmm_tools
      backup_dir                              /mmm_backup
      restore_dir                             /DATABASE
</host>
<copy_method scp>
  backup_command scp -c blowfish -r %SSH_USER%@%IP%:%SNAPSHOT%/%CLONE_DIR% 
%DEST_DIR%/
  restore_command cp -axv %BACKUP_DIR%/* %DEST_DIR%/
      true_copy 1
</copy_method>
<copy_method rdiff>
      backup_command rdiff-backup --ssh-no-compression -v 5 !--include 
%SNAPSHOT%/%CLONE_DIR%! --exclude %SNAPSHOT% %SSH_USER%@%IP%::%SNAPSHOT%/ %DEST_DIR%/
      restore_command rdiff-backup --force -v 5 -r %VERSION% %BACKUP_DIR% 
%DEST_DIR%/.mmm_restore; cp -axvl --remove-destination %DEST_DIR%/.mmm_restore/* 
 %DEST_DIR%/; rm -r %DEST_DIR%/.mmm_restore/
      incremental_command rdiff-backup --parsable-output -l %BACKUP_DIR%
      single_run 1
      incremental 1
</copy_method>
<copy_method ssh-gz>
      backup_command ssh -c blowfish %SSH_USER%@%IP% "cd '%SNAPSHOT%'; tar cv !'
%CLONE_DIR%'!" | gzip > %DEST_DIR%/backup.tar.gz
      restore_command cd %DEST_DIR%; tar xzfv %BACKUP_DIR%/backup.tar.gz
      single_run 1
</copy_method>
  • /etc/mysql-mmm/mmm_mon.conf (solo la máquina que tenga el rol de monitor)
include mmm_common.conf
<monitor>
      ip                                      127.0.0.1
      pid_path                                /var/run/mmm_mond.pid
      bin_path                                /usr/lib/mysql-mmm/
      status_path                             /var/lib/misc/mmm_mond.status
      ping_ips                                192.168.1.242, 192.168.1.243
</monitor>
<host default>
      monitor_user                    mmm_monitor
      monitor_password                mmm_monitor
</host>
debug 0

Enlaces externos