# rm-rf.es | Administración de sistemas

Blog de un SysAdmin Unix, Gnu/Linux, Windows y lo que haga falta.

Uso avanzado del comando wget

En lugar de limitarnos a descargar un único fichero con wget, podemos hacer un uso avanzado del comando y sacar todo su potencial, que seguro que en algún momento nos viene bien y facilita alguna tarea.

En su día ya os enseñé la forma de limitar la velocidad de descarga con wget así que eso nos lo saltamos. Ahí van algunos usos avanzados o menos conocidos de wget.

Descargar una página completa junto a todas sus dependencias

Es decir, si descargamos un HTML usando wget a secas, descargaremos la página HTML pero no las imágenes, CSS, javascript, etc a las que hace referencia. El parámetro “-p” o “–page-requisites” descarga todo este contenido. Si además añadimos el parámetro “–convert-links”, los links se convertirán para que funcionen en local una vez descargados. También podemos hacer un backup de los links anteriores con “–backup-converted”:

$ wget --page-requisites --backup-converted http://rm-rf.es
$ ls -l
total 4
drwxrwxr-x 3 alex alex 4096 Aug 22 19:02 rm-rf.es
$ ls -lR *
rm-rf.es:
total 68
-rw-rw-r-- 1 alex alex 60519 Aug 21 22:55 index.html
-rw-rw-r-- 1 alex alex   242 Apr 28  2011 robots.txt
drwxrwxr-x 3 alex alex  4096 Aug 22 19:02 wp-content

rm-rf.es/wp-content:
total 4
drwxrwxr-x 3 alex alex 4096 Aug 22 19:02 themes
[...]

Descargar un website completo

En este caso más que un website completo, lo que podemos hacer es especificar por parámetro el número de niveles que recorrerá wget y descargará todo lo que encuentre en ellos, podemos especificar N niveles, todo ello se descargará en local creando una copia exacta/mirror del website que descargamos. Jugaremos con estos dos parámetros:

  -r,  --recursive          specify recursive download.
  -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).

Si quiero descargar por ejemplo 4 niveles de un sitio web:

$ wget -r -l 4 http://google.es/

También puedo guardar un log de las operaciones con “-o “:

$ wget -r -l 4 http://google.es/ -o descarga_website.log

También es bueno combinarlo con “–convert-links”.

Descargar página junto con las cabeceras del servidor

Podemos hacer que las cabeceras se van directamente en la salida del comando:

$ wget -S http://www.google.com/

--2014-08-22 19:12:23--  http://www.google.com/
Resolving www.google.com (www.google.com)... .173.194.45.50, 173.194.45.51, 173.194.45.49, ...
Connecting to www.google.com (www.google.com)|173.194.45.50|:80... connected.
HTTP request sent, awaiting response... 
  HTTP/1.1 302 Found
  Cache-Control: private
  Content-Type: text/html; charset=UTF-8
  Location: http://www.google.es/?gfe_rd=cr&ei=93n3U4rCJ8TI8gfH-oDwBQ
  Content-Length: 258
[...]

O guardarlas en el fichero resultante:

$ wget --save-headers http://www.google.com/
$ more google.com/index.html
$ more index.html.2 
HTTP/1.1 200 OK
Date: Fri, 22 Aug 2014 17:13:02 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: PREF=ID=dac6e5ce9196e48f:FF=0:TM=1408727582:LM=1408727582:S=pWmR-xujz_ZeT8Bv; expires=Sun, 21-Aug-2016 17:13:02 GMT; path=/; domain=.google.es
Set-Cookie: NID=67=Ek0aw0c0biQWMw-C_RoxO1QEiIdvl54
[...]

Descargar sólo ficheros con una extensión concreta

Los comodines en la URL no nos van a funcionar, para ello debemos usar “-A” seguido de las extensiones a descargar de un directorio concreto, separadas por comas:

wget -r -P /var/tmp -A jpg,jpeg,gif,png http://www.foo.com/imagenes/

Como veis también podemos forzar la ruta de descarga. Así descargamos todas las imágenes del sitio a un directorio local.

Reaunar una descarga cancelada a mitad

Poco más que añadir, si cancelamos una descarga a mitad podemos seguir donde lo hemos dejado con el siguiente comando:

$ wget -nc -r http://www.foo.com/

Mostrar el contenido de la página por STDOUT en lugar de descargarlo

wget -O - http://google.es

Descargar URLs de un fichero de texto

Si tenemos un fichero de txt con un listado de URLs (una en cada línea), podemos descargar todas de vez con el parámetro “-i”:

$ more urls.txt 

http://google.es


http://marca.com

$ wget -i urls.txt
--2014-08-22 19:25:26--  http://google.es/
Resolving google.es (google.es)... 173.194.41.239, 173.194.41.255, 173.194.41.248, ...
Connecting to google.es (google.es)|173.194.41.239|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: http://www.google.es/ [following]
--2014-08-22 19:25:26--  http://www.google.es/
Resolving www.google.es (www.google.es)... 173.194.45.47, 173.194.45.56, 
[...]

--2014-08-22 19:25:26--  http://marca.com/
Resolving marca.com (marca.com)... 193.110.128.199, 2001:67c:2294:1000::f199
Connecting to marca.com (marca.com)|193.110.128.199|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
[...]

Y de momento no se me ocurren más, si sabéis vosotros alguno más, comentadlo!

¿RHEL 7 ó CentOS 7 para 32 bit?

redhat logoLa respuesta oficial es clara: NO.

RHEL (y por consiguiente CentOS y derivados) ha eliminado la versión de 32 bit para máquinas Intel x86 de la versión 7 del sistema operativo. El soporte para esta nueva versión se limita a máquinas de 64 bit, aunque ya confirmaron en su día que sí que hay soporte integrado para librerías de 32bit lo que permite seguir ejecutando aplicaciones de 32bit. Los usuarios que quieran seguir con 32 bit deberán seguir en las ramas 5.x y 6.x de los sistemas operativos.

De todas formas ya sabemos que CentOS tiene una gran comunidad detrás,  y ya existe una BETA i686 que se puede probar a partir de este repositorio. Como mi laptop personal es de 32 bit voy a bajarla y probarla a ver que me encuentro, aunque es un repositorio de velocidad extremadamente lenta, debe ser un servidor totalmente casero, 10 horas para 372MB ;)

Respuesta oficial de Red Hat:

Red Hat Enterprise Linux 7 will only provide 64-bit ISO’s, thus allowing only a 64-bit operating environment. However, 32-bit is supported in the following ways:

  • RHEL 7 will continue to provide selected libraries in both 32-bit and 64-bit, allowing 32-bit applications to run in the 64-bit RHEL 7 OS environment. This functionality also exists for RHEL 5 & 6 as documented in the knowledge article: How to install 32-bit packages on a 64-bit system
  • RHEL 7 will continue to support the multilib toolchain, allowing applications to be compiled for both 32-bit and 64-bit.
  • RHEL 7 can host, using KVM virtualization technology, both 32-bit and 64-bit virtual guest instances of RHEL 5 and RHEL 6.

Cómo generar un SSL Certificate Request (CSR) en Tomcat

Estos son los pasos para generar un CSR (SSL Certificate Request) en Tomcat. Este tutorial se basa en la creación de un nuevo keystore.

Lo primero es crear el keystore que almacenará el certificado y la private key. El comando a utilizar para todas las operaciones es keytool. Forzamos el tamaño de la private key a 2048 bits con el parámetro keysize, le indicamos que el algoritmo es RSA y que el alias para el certificado dentro del keystore es “tomcat”:

# keytool -genkey -alias tomcat -keyalg RSA -keysize 2048 \
-keystore /usr/share/tomcat/conf/ssl/tomcat_keystore
Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  www.rm-rf.es
What is the name of your organizational unit?
  [Unknown]:  IT
What is the name of your organization?
  [Unknown]:  Mi compañía
What is the name of your City or Locality?
  [Unknown]:  Madrid
What is the name of your State or Province?
  [Unknown]:  Madrid
What is the two-letter country code for this unit?
  [Unknown]:  ES
Is CN=www.rm-rf.es, OU=IT, O=Mi compañía, L=Madrid, ST=Madrid, C=ES correct?
  [no]:  yes

Enter key password for 
	(RETURN if same as keystore password):  

Como podéis ver, solicita el password del keystore (lo utilizaremos para acceder a los contenidos del mismo), el Common Name para el certificado (first and last name, un poco ambiguo…), y el resto de datos de organización, empresa, ciudad, etc. Finalmente la clave para la key, que podemos seleccionar la misma que para el keystore.

Con esto ya tenemos el keystore creado y la private key con todos los datos. Podemos asegurarnos listando el contenido del keystore:

# keytool -list -keystore /usr/share/tomcat/conf/ssl/tomcat_keystore
Enter keystore password:  

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

tomcat, 21-ago-2014, PrivateKeyEntry, 
Certificate fingerprint (SHA1): 9C:B1:.......

Para generar el CSR a partir de esa información ejecutamos el siguiente comando:

# keytool -certreq -keyalg RSA -alias tomcat -file /usr/share/tomcat/conf/ssl/certreq.csr \
-keystore /usr/share/tomcat/conf/ssl/tomcat_keystore

Una vez ejecutado ya tendremos el fichero .csr que se envía a las empresas certificadoras para que emitan el certificado SSL.

# cat  /usr/share/tomcat/conf/ssl/certreq.csr
-----BEGIN NEW CERTIFICATE REQUEST-----
[...]
-----END NEW CERTIFICATE REQUEST-----

URL Rewriting / Reescritura de URL en Tomcat

Normalmente cuando trabajamos con un servidor de aplicaciones Tomcat, jBOSS, etc tenemos por delante un servidor web Apache para todo lo relacionado con URL Rewriting/Reescritura de URL, funciones de Proxy, etc. ¿Qué pasa si queremos hacer el url-rewrite directamente en Tomcat sin un frontal web?

Tomcat por defecto no dispone de función de reescritura de URLs, es necesario instalar un filtro web Java llamado UrlRewriteFilter. Vamos a ver su instalación y configuración.

Descargamos el filtro:

# wget http://urlrewritefilter.googlecode.com/files/urlrewritefilter-4.0.3.jar

El filtro debe estar junto con el restro de .jar, en el caso de Debian lo movemos a la ruta donde están los jar de JAVA y hacemos un link simbólico en la ruta lib/ de tomcat. Si queréis lo podéis poner directamente en el lib/

# ls -l /usr/share/java/urlrewritefilter-4.0.3.jar
-rw-r--r-- 1 root root 177497 jul  2  2012 /usr/share/java/urlrewritefilter-4.0.3.jar

# ls -l /usr/share/tomcat7/lib/urlrewritefilter-4.0.3.jar
lrwxrwxrwx 1 root root 37 ago 20 10:02 /usr/share/tomcat7/lib/urlrewritefilter-4.0.3.jar -> ../../java/urlrewritefilter-4.0.3.jar

Ahora ya podemos configurar la aplicación que queremos que disponga del filtro URL Rewrite. Hay que modificar el fichero web.xml y añadir el filtro:

<filter>
      <filter-name>UrlRewriteFilter</filter-name>
      <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
      <filter-name>UrlRewriteFilter</filter-name>
      <url-pattern>/*</url-pattern>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Y por último creamos el fichero urlrewrite.xml en el mismo directorio que el web.xml y en él configuramos los filtros que estimemos oportunos. En este caso podéis ver un filtro para forzar el dominio con “www”:

<urlrewrite>
    <rule>
      <name>seo redirect</name>
      <condition name="host" operator="notequal">^www.test.com</condition>
      <condition name="host" operator="notequal">^localhost</condition>
      <from>^/(.*)</from>
      <to type="permanent-redirect" last="true">http://www.test.com/$1</to>
    </rule>
</urlrewrite>

Otro ejemplo, redirección de una URL:

<urlrewrite>
    <rule>
      <from>^/url-antigua/foo/index\.html$</from>
      <to type="redirect">/url-nueva/bar//index.html</to>
   </rule>
</urlrewrite>

Más ejemplos aquí.

Una vez configurado todo, se reinicia Tomcat y verifica el funcionamiento de los rewrites.

Mapeo persistente de dispositivos / discos con udev

En ocasiones, pueden no ser suficiente con disponer de un identificador fijo para un filesystem (blkid, uuid, ya sabéis), sino que necesitamos un identificador fijo para el dispositivo o disco.

Puede haber casos en los que puede ser válido utilizar las nomenclaturas disponibles en la ruta /dev/disk:

$ ls -l /dev/disk/
total 0
drwxr-xr-x 2 root root 600 2014-08-19 07:40 by-id
drwxr-xr-x 2 root root  80 2014-08-19 09:38 by-label
drwxr-xr-x 2 root root 240 2014-08-19 09:38 by-path
drwxr-xr-x 2 root root 180 2014-08-19 07:40 by-uuid

Como véis, encontramos los discos identificados por “id“, “label“, “path” y “uuid“. Ejemplo:

$ ls -lR /dev/disk/*
/dev/disk/by-id:
total 0
lrwxrwxrwx 1 root root  9 2014-08-19 07:39 ata-ST9320423AS_5VH5928G -> ../../sda
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 ata-ST9320423AS_5VH5928G-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 ata-ST9320423AS_5VH5928G-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 ata-ST9320423AS_5VH5928G-part3 -> ../../sda3
[...]

/dev/disk/by-label:
total 0
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 storage -> ../../sda1
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 System\x20Reserved -> ../../sda2

/dev/disk/by-path:
total 0
lrwxrwxrwx 1 root root  9 2014-08-19 07:39 pci-0000:00:1a.0-usb-0:1.2:1.0-scsi-0:0:0:0 -> ../../sdb
lrwxrwxrwx 1 root root  9 2014-08-19 07:39 pci-0000:00:1f.2-scsi-0:0:0:0 -> ../../sda
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 pci-0000:00:1f.2-scsi-0:0:0:0-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 pci-0000:00:1f.2-scsi-0:0:0:0-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 pci-0000:00:1f.2-scsi-0:0:0:0-part3 -> ../../sda3
[...]

/dev/disk/by-uuid:
total 0
lrwxrwxrwx 1 root root 10 2014-08-19 07:40 278b1de4-fd78-41b6-9271-fda3ebe31b9b -> ../../sda6
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 583fb8a1-4935-4e01-bef4-49bd8ffd27c1 -> ../../sda7
lrwxrwxrwx 1 root root 10 2014-08-19 07:40 9f7b446b-6852-4840-96e0-5d8045926b44 -> ../../dm-0
lrwxrwxrwx 1 root root 10 2014-08-19 07:39 a78dc39a-ffa1-4f89-baa3-29673b084c7c -> ../../sda5
[...]

Si esto no es suficiente, podemos recurrir a “udev” y su capacidad de asignar identificadores fijos a dispositivos (no sólo a discos, también a tarjetas de red por ejemplo). Para dar un mapeo fijo a un disco lo primero es conocer su scsi_id (identificador único SCSI):

# /sbin/scsi_id --whitelisted --replace-whitespace /dev/sdj
3600144f0956df03d000053eac12d0003

Ahora que tenemos el SCSI_ID, creamos un nuevo fichero con las reglas udev, hay un directorio específico para añadir nuestras reglas personalizadas:

/etc/udev/rules.d/20-persistent-disk.rules

En el fichero indicado, añadimos las siguientes líneas:

KERNEL=="sd[a-z]", SUBSYSTEM=="block", PROGRAM="/sbin/scsi_id --whitelisted --replace-whitespace /dev/$name", RESULT=="3600144f0956df03d000053eac12d0003", NAME="persistente"
KERNEL=="sd[a-z][0-9]", SUBSYSTEM=="block", PROGRAM="/sbin/scsi_id --whitelisted --replace-whitespace /dev/$name", RESULT=="3600144f0956df03d000053eac12d0003", NAME="persistente%n"

Básicamente, en la primera línea estamos diciendo que el dispositivo de bloques que sea sd* y su SCSI_ID sea el que hemos sacado antes, le asigne el nombre permanente /dev/persistente. La segunda línea es para sus particiones, le asignará /dev/persistente1, /dev/persistente2, etc.

Finalmente recargamos las reglas de udev con el siguiente comando:

# udevadm control --reload-rules

Y ya deberíamos ver nuestro dispositivo con nombre persistente:

# ls -l /dev/persistente
brw-rw---- 1 root disk 8, 32 ago 12 20:03 /dev/persistente

Nota: cuando asignas un nombre persistente, es posible que el disco (/dev/sd*) ya no aparezca al hacer un fdisk, por lo menos a mí me ha pasado.

Cómo configurar un Smarthost / Relayhost en Postfix

Configurar un Smarthost en Postfix es muy sencillo, podemos hacerlo de forma dinámica editando la configuración con el comando “postconf” o modificando directamente el fichero de configuración main.cf.

El parámetro o directiva a modificar es el mismo en ambos casos, “relayhost“. Pongamos el caso de que queremos configurar como Smarthost el servidor 10.10.10.100. Con postconf ejecutaríamos lo siguiente:

# postconf -e "relayhost = 10.10.10.100"

Y si quisieramos modificar directamente el fichero de configuración, normalmente ubicado en /etc/postfix/main.cf, añadiríamos:

relayhost = 10.10.10.100

Reiniciamos Postfix y ya lo tenemos, todo el correo de nuestro servidor Postfix se redirigirá al Smarthost.

Si quisieramos configurar el Smarthost por dominio se requiere algo más de configuración. Lo primero es especificar el dominio y su Smarthost+puerto en el fichero transport:

# fichero: /etc/postfix/transport
midominio.com smtp:10.10.10.100:25

Y después, al igual que con la reescritura de direcciones de correo en Postfix, generamos la tabla/base de datos con dicha información y especificamos en el fichero main.cf dicha tabla de transporte:

# postmap hash:/etc/postfix/transport
# fichero: main.cf:
transport_maps = hash:/etc/postfix/transport

Reiniciamos postfix y a funcionar.

Configurar umask para sesiones SFTP

Si necesitamos configurar un umask determinado para los usuarios SFTP, debemos tener en cuenta que los cambios que realicemos a nivel de .bashrc no serán válidos para estos usuarios, debido a que no abren una shell al establecer conexión vía SFTP.

A partir de la versión 5.4 de OpenSSH podemos establecer el parámetro umask en la configuración del servidor ssh (sshd_config). Así por ejemplo si quisieramos establecer un umask de 0022 lo podemos hacer añadiendo la siguiente línea al fichero. En Red Hat y derivados se encuentra en /etc/ssh/sshd_config:

Subsystem sftp internal-sftp -u 0022

Y reiniciar el servicio SSH:

# service sshd restart

En versiones anteriores como la 5.3, he conseguido hacerlo funcionar con la siguiente configuración en lugar de la anterior:

Subsystem sftp internal-sftp -l VERBOSE -f LOCAL6 -u 000

Y en la documentación de OpenSSH recomiendan esta otra que también podéis probar si tenéis problemas:

Subsystem sftp /bin/sh -c 'umask 0022; /usr/libexec/openssh/sftp-server'

Elegir la versión de java JRE por defecto (Red Hat con múltiples versiones)

Si necesitamos varias versiones del JRE (Java Runtime Environment) de java en un servidor Red Hat y derivados (CentOS, Fedora, Scientific Linux,etc) es necesario conocer el modo de configurar una de ellas para ser la utilizada por defecto.

En el siguiente ejemplo tenemos un servidor con tres versiones de java JRE:

  •  jre-1.5.0
  • jre-1.6.0
  • jre-1.7.0

Para verificar este punto, y saber cual es la versión que está seleccionada por defecto en el sistema utilizamos el comando “alternatives“, que nos muestra tanto el listado de versiones de un programa/servicio concreto como el que está seleccionado por defecto. También tenemos la opción de modificar la versión y establecer la que queramos:

# /usr/sbin/alternatives --config java

There are 3 programs which provide 'java'.
Selection Command
-----------------------------------------------

1 /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java
2 /usr/lib/jvm/jre-1.5.0-gcj/bin/java
*+ 3 /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java

Enter to keep the current selection[+], or type selection number: 1

Si a continuación consultamos la versión de java sin forzar el path vemos que efectivamente la ha modificado:

# java -version
java version "1.6.0_30"
OpenJDK Runtime Environment (IcedTea6 1.13.3) (rhel-5.1.13.3.el6_5-x86_64)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)

También podéis listar la información de versiones si necesidad de entrar en el config, pero el volcado de datos es un poco más tosco:

# alternatives --display java
java - status is auto.
 link currently points to /usr/lib/jvm/jre-1.7.0-openjdk/bin/java
/usr/lib/jvm/jre-1.5.0-gcj/bin/java - priority 1500
 slave keytool: /usr/lib/jvm/jre-1.5.0-gcj/bin/keytool
 slave orbd: (null)
 slave pack200: (null)
 slave rmid: (null)
 slave rmiregistry: /usr/lib/jvm/jre-1.5.0-gcj/bin/rmiregistry
 slave servertool: (null)
 slave tnameserv: (null)
 slave unpack200: (null)
 slave jre_exports: /usr/lib/jvm-exports/jre-1.5.0-gcj
 slave jre: /usr/lib/jvm/jre-1.5.0-gcj
 slave java.1.gz: (null)
 slave keytool.1.gz: (null)
 slave orbd.1.gz: (null)
 slave pack200.1.gz: (null)
 slave rmid.1.gz: (null)
 slave rmiregistry.1.gz: (null)
 slave servertool.1.gz: (null)
 slave tnameserv.1.gz: (null)
 slave unpack200.1.gz: (null)
/usr/lib/jvm/jre-1.7.0-openjdk/bin/java - priority 170009
 slave keytool: /usr/lib/jvm/jre-1.7.0-openjdk/bin/keytool
 slave orbd: /usr/lib/jvm/jre-1.7.0-openjdk/bin/orbd
 slave pack200: /usr/lib/jvm/jre-1.7.0-openjdk/bin/pack200
 slave rmid: /usr/lib/jvm/jre-1.7.0-openjdk/bin/rmid
 slave rmiregistry: /usr/lib/jvm/jre-1.7.0-openjdk/bin/rmiregistry
 slave servertool: /usr/lib/jvm/jre-1.7.0-openjdk/bin/servertool
 slave tnameserv: /usr/lib/jvm/jre-1.7.0-openjdk/bin/tnameserv
 slave unpack200: /usr/lib/jvm/jre-1.7.0-openjdk/bin/unpack200
 slave jre_exports: /usr/lib/jvm-exports/jre-1.7.0-openjdk
 slave jre: /usr/lib/jvm/jre-1.7.0-openjdk
 slave java.1.gz: /usr/share/man/man1/java-java-1.7.0-openjdk.1.gz
 slave keytool.1.gz: /usr/share/man/man1/keytool-java-1.7.0-openjdk.1.gz
[...]