How To

Come fare un mirror Ubuntu itinerante

Questa guida cerca di spiegare come ho fatto a fare il mirror Ubuntu e proxy server che abbiamo usato la prima volta al Linux Day 2009. I mirror normalmente risiedono in una server farm, hanno un nome ed un indirizzo IP pubblico ben noti e stanno lì fino alla fine della loro vita. In questo caso io volevo invece un mirror da portarsi in giro durante le varie manifestazioni, cosa che pone alcuni problemi aggiuntivi affrontati in questa guida, da cui il nome "itinerante".

Attenzione: non è una guida per principianti, dà per scontato che sappiate usare la shell, l'utente root, un editor di testi non grafico ed alcune altre cosette. Nulla di trascendentale per uno smanettone, ma una barriera insormontabile per chi ha visto sempre e solo Windows...

Indice

 

Hardware

Io ho usato il mio vecchio Athlon 800 con 896 mega di RAM e gli ho aggiunto un paio di dischi, per un totale di 270 giga circa di storage. Non credo siano necessari 896 mega di RAM, ma visto l'ottimo uso che il kernel Linux fa della RAM quando è libera (la usa come cache del disco) e visto che dei moduli PC133 non sapevo cos'altro farmene glieli ho lasciati, male non fanno. Una scheda ethernet c'era già, una gliel'ho aggiunta.

In linea di massima comunque penso che la configurazione minima possa essere:

  • Qualsiasi CPU dal Pentium MMX in poi
  • 128 mega di RAM
  • 100 giga di disco (ma dipende da quanta roba volete sul mirror)
  • due schede ethernet
  • tastiera, monitor e lettore CD per l'installazione, dopo non servono più

Configurazione del BIOS

Ogni interfaccia del BIOS è diversa dalle altre, quindi non posso essere preciso qui. Dico solo cosa ho impostato nel BIOS, senza dettagliare il come, che trovate scritto sul manuale del vostro PC.

  • Avvio automatico del PC ogni giorno alle ore 20.00 (per fargli aggiornare il mirror di notte)
  • Riavvio automatico del PC se manca la corrente
  • Boot da CD

Installazione

Anche qui non scendo in dettagli, solo perché questa non è una guida per l'installazione di Linux. Ho usato una Debian Lenny su CD. Il sistema e la swap li ho messi in RAID 1 (detto anche mirroring, ma in questa guida il termine "mirroring" si confonderebbe facilmente con il mirror dei pacchetti, con il quale in realtà non condivide nulla). Ho usato un sistema RAID 1 solo per evitare di dover rifare l'installazione se dovesse rompersi un disco. La swap in RAID 1 è utile perché in caso di danneggiamento di solo qualche settore del disco, avere la swap corrotta sortirebbe gli stessi effetti di un guasto alla memoria RAM, che di solito su Linux si traduce nella corruzione del filesystem e quindi nella necessità di reinstallare tutto il sistema.

Resta da chiedersi per quale motivo io abbia impostato un'area di swap su un mirror con 896 mega di RAM, pensato per le installazioni in piccole LAN. Non lo so, paranoia forse, o semplicemente il fatto che se dovessero servirmi dei moduli RAM PC133 potrei tranquillamente toglierli da quel PC perché tanto all'occorrenza ha la swap.

Ho quindi creato due piccoli volumi RAID 1 software, uno da 2 giga per il sistema ed uno da 1 giga per la swap. Il resto dello spazio disponibile l'ho gestito come un volume unico attraverso LVM. Tutta la gestione dei RAID 1 e di LVM l'ho fatta durante l'installazione scegliendo il partizionamento manuale e usando i menù a disposizione.

I dischi li ho partizionati durante l'installazione nel seguente modo:

Disk /dev/hda: 80.0 GB, 80026361856 bytes
/dev/hda1 * 1 243 1951866 fd Linux raid autodetect
/dev/hda2 244 9604 75192232+ 8e Linux LVM
/dev/hda3 9605 9729 1004062+ fd Linux raid autodetect
Disk /dev/hde: 80.0 GB, 80026361856 bytes
/dev/hde1 * 1 243 1951866 fd Linux raid autodetect
/dev/hde2 244 9604 75192232+ 8e Linux LVM
/dev/hde3 9605 9729 1004062+ fd Linux raid autodetect
Disk /dev/hdg: 122.9 GB, 122942324736 bytes
/dev/hdg1 1 14946 120053713+ 8e Linux LVM

Il volume LVM risultante l'ho montato sotto la directory /cache. Avrei potuto (o forse dovuto, dal punto di vista degli standard) montarlo sotto /mnt/cache o /srv: in realtà non cambia nulla, basta saperlo.

Configurazione delle schede ethernet

Non importa come hai scelto di configurare le schede di rete in fase di installazione, tanto dovrai rifare tutto...

Diamo un nome chiaro ad ogni scheda

Una volta installato il sistema, le due schede di rete sono nominate eth0 ed eth1. Conviene chiamarle lan e wan, in modo da evitare errori durante le configurazioni degli altri software. Cambiamo quindi il file

/etc/udev/rules.d/70-persistent-net.rules 

e scriviamo wan al posto di eth0 e lan al posto di eth1. Riavviamo il computer e le schede avranno il nuovo nome. Ora colleghiamo il PC ad uno switch o router acceso con un cavo ethernet, inserendolo in una delle due schede di rete e verifichiamo che si accenda un led verde o rosso vicino alla presa ethernet dove abbiamo inserito il cavo. Il comando

# mii-tool lan

ci dice se la scheda che abbiamo chiamato lan abbia un cavo inserito o meno ("No link" significa che il cavo non c'è). In questo modo possiamo capire quale delle due schede di rete si chiama lan e quale wan. Possiamo mettere un etichetta adesiva con scritto "LAN" vicino alla presa della scheda che si chiama lan, così sapremo dove collegare il cavo della rete locale quando saremo al Linux Day. Sull'altra scheda dovremo collegare il cavo che va verso il router con connessione internet

Configuriamo l'indirizzo IP

La scheda LAN dovrà avere un indirizzo IP fisso e configurato manualmente, mentre la scheda wan dovrà essere impostata in DHCP in modo da prendere un indirizzo in automatico ad ogni boot.

Riporto qui il mio file /etc/network/interfaces, ovviamente potete scegliere di usare una classe di indirizzi diversa nella rete locale, ma in quel caso ricordatevi di usare la classe che avete scelto anche nel resto di questa guida:

 # This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto wan
iface wan inet dhcp

auto lan
iface lan inet static
address 10.151.44.254
netmask 255.255.255.0

Fatto questo possiamo collegare il cavo ethernet alla scheda WAN e riavviare i servizi di rete:

# /etc/init.d/networking restart

Soluzioni software adottate

Il problema più difficile da risolvere era l'installazione di Ubuntu per terzi durante il Linux Day prendendo i pacchetti dal mirror locale. La soluzione classica, ovvero quella di specificare un mirror manualmente in Ubuntu, non era ottimale, perché il computer su cui veniva installato Ubuntu, durante un evento come il Linux Day, è un computer che nel resto della sua vita non disporrà del mirror locale, ma dovrà scaricare i pacchetti da uno dei mirror ufficiali. Cambiando a mano il mirror in fase di installazione si andava incontro ad almeno questi problemi:

  • Non tutti sono in grado di installare Ubuntu specificando un mirror manuale, quindi avrei dovuto prima fare un minicorso agli installatori
  • Specificando a mano un mirror la procedura d'installazione di Ubuntu non è più quella predefinita, quindi richiede più tempo, almeno per cliccare sui tasti giusti invece che semplicemente fare "avanti, avanti, avanti"
  • Dopo l'installazione è necessario reimpostare il mirror ufficiale, altrimenti quando il proprietario del computer cercherà di usarlo a casa sua non riuscirà a fare gli aggiornamenti e ad aggiungere alcun software. Il rischio è quello di dimenticarsi di reimpostare il mirror in Ubuntu.

Per questi motivi è necessario che il nostro mirror agisca da router e fornisca una rete locale, ingannando i vari Ubuntu che vengono installati in tale rete e facendogli credere che *.archive.ubuntu.com (ovvero uno qualsiasi dei mirror ufficiali di Ubuntu) sia in realtà il mirror locale della LAN.

A questo punto, dovendo fare da router e da DNS, tanto valeva che facesse anche da proxy trasparente HTTP, in modo da velocizzare anche la normale navigazione durante il Linux Day.

I software che ho usato sono:

  • debmirror, per tenere aggiornato il mirror
  • uno script richiamato in /etc/rc.local per far partire automaticamente l'aggiornamento del mirror ad ogni boot
  • Bind 9 per fornire servizio DNS con *.archive.ubuntu.com fasullo
  • Apache 2 per pubblicare il mirror su protocollo HTTP
  • DHCP3 Server per fornire servizio DHCP all'interno della LAN e comunicare il DNS corretto ai vari PC, ovvero quello fasullo di cui sopra
  • squid per offrire servizio di proxy HTTP trasparente
  • iptables per configurare il routing attraverso il proxy/mirror stesso e per l'invio dei pacchetti rilevanti a squid

Di seguito si vedranno i dettagli di configurazione dei software qui elencati. Sei hai già ben chiaro come configurare uno o più di questi software, puoi tranquillamente saltare la sezione reativa ad esso e fare tu nel modo che ritieni migliore.

debmirror

L'installazione avviene con il solito

apt-get install debmirror

Questo software non necessita di configurazione, basta passare tutto il necessario sulla linea di comando. Io lo richiamo così:

/usr/bin/debmirror --progress --verbose --method=http --root=/ftp/mirror/ubuntu --host=mirror.switch.ch \
--dist=jaunty,jaunty-updates,jaunty-backports,jaunty-proposed,jaunty-security,karmic,karmic-updates,karmic- \
backports,karmic-proposed,karmic-security --section=main,restricted,universe,multiverse --arch=i386,amd64 \
--getcontents --ignore-release-gpg /cache/mirrors/ubuntu

Dove le \ alla fine della riga non sono da scrivere, ma sono una convenzione tipografica per dire che è un comando unico e va scritto tutto su una sola riga.

Ho scelto di fare il mirror prendendolo da SWITCH perché è un mirror geograficamente abbastanza vicino che nel mio caso ha sempre funzionato meglio di altri geograficamente più vicini a me. Se scegliete un altro mirror ufficiale diverso da SWITCH verificate prima che la root directory sia /ftp/mirror/ubuntu e se è diversa cambiatela nel comando debmirror.

Da notare che ho scelto di salvare i files scaricati in /cache/mirrors/ubuntu, quindi sarà necessario creare prima tale directory.

lo script per debmirror

Per richiamare automaticamente il comando debmirror ad ogni boot, l'ho messo in uno script. Nello stesso script ho aggiunto anche il comando per fare il mirror di medibuntu. Ho salvato questo file come /usr/local/bin/startdebmirroring.sh:

#!/bin/bash

if [ -f /etc/stopmirror ] ; then
exit 0
fi

/usr/bin/debmirror --progress --verbose --method=http --root=/ --host=packages.medibuntu.org \
--dist=jaunty,karmic --section=free,non-free --arch=i386,amd64 --getcontents --ignore-release-gpg \
/cache/mirrors/medibuntu

if [ -f /etc/stopmirror ] ; then
exit 0
fi

/usr/bin/debmirror --progress --verbose --method=http --root=/ftp/mirror/ubuntu --host=mirror.switch.ch \
--dist=jaunty,jaunty-updates,jaunty-backports,jaunty-proposed,jaunty-security,karmic,karmic-updates,karmic- \
backports,karmic-proposed,karmic-security --section=main,restricted,universe,multiverse --arch=i386,amd64 \
--getcontents --ignore-release-gpg /cache/mirrors/ubuntu

/bin/sleep 300s

if [ -f /etc/stopmirror ] ; then
exit 0
fi

/sbin/init 0

Forse lo stile di programmazione non è il meglio disponibile, ma è facile da leggere. Per fermare l'aggiornamento del mirror è sufficiente creare un file che si chiami /etc/stopmirror (utile per non avere la procedura di aggiornamento che gira durante il Linux Day). Questo script spegne il computer dopo aver finito di aggiornare il mirror, in questo modo non consumiamo corrente inutilmente. La pausa di cinque minuti (300 secondi) prima di spegnere serve in caso di mancanza di connettività internet: in quel caso, senza tale pausa, lo script arriverebbe alla fine in pochi secondi e spegnerebbe il PC, rendendo ardua l'impresa di collegarsi via ssh per creare il file /etc/stopmirror. Ora diamo il permesso di esecuzione per questo file

# chmod +x /usr/local/bin/startdebmirroring.sh

Per far partire l'aggiornamento del mirror in modo automatico quando il computer si avvia, dobbiamo richiamare lo script all'interno di /etc/rc.local. È comodo poter monitorare l'andamento della procedura anche collegandosi via ssh, quindi è utile che l'aggiornamento non occupi una console virtuale vera e propria, ma che funzioni sotto il comando screen, per poter richiamare il suo output anche quando non c'è una tastiera ed un monitor attaccati al proxy. Installiamo il necessario:

# apt-get install openssh-server screen

Ora possiamo richiamare lo script, aggiungendo questa riga in rc.local prima del comando exit, usando screen in modo che non occupi una console:

/usr/bin/screen -S debmirrors -d -m /usr/local/bin/startdebmirroring.sh

Bind 9

Il mirror/proxy fornisce servizio DNS grazie a ISC Bind. Come detto prima, questo DNS però dovrà ingannare i computer in rete locale e fargli credere che *.archive.ubuntu.com sia il mirror locale. Per ottenere ciò dobbiamo dire che questo DNS è il master della zona archive.ubuntu.com e poi definire un appropriato database della zona.

Dopo aver installato Bind

# apt-get install bind9 bind9utils

modifichiamo il file delle zone

# nano /etc/bind/named.conf.local

mettendo le dichiarazioni delle varie zone di cui vogliamo che questo DNS sia il master:

zone "internal.pinerolo.linux.it" {
type master;
file "/etc/bind/db.internal.pinerolo.linux.it";
};

zone "archive.ubuntu.com" {
type master;
file "/etc/bind/db.archive.ubuntu.com";
};

zone "security.ubuntu.com" {
type master;
file "/etc/bind/db.security.ubuntu.com";
};

zone "packages.medibuntu.org" {
type master;
file "/etc/bind/db.packages.medibuntu.org";
};

In questo caso ho aggiunto la zona packages.medibuntu.org perché, come visto prima, ho deciso di fare il mirror anche di medibuntu. La zona internal.pinerolo.linux.it serve solo per la LAN, l'avevo definita pensando ad eventuali altri sviluppi di questo mirror/proxy, poi non l'ho mai usata. Seguono i files che definiscono i database delle varie zone.

  • db.internal.pinerolo.linux.it
; BIND db file for internal.pinerolo.linux.it

$TTL 86400

@ IN SOA proxy.internal.pinerolo.linux.it. info.pinerolo.linux.it. (
2009101802  ; serial number YYMMDDNN
28800  ; Refresh
7200  ; Retry
864000  ; Expire
86400  ; Min TTL
)

NS proxy.internal.pinerolo.linux.it.


internal.pinerolo.linux.it. IN A 10.151.44.254

$ORIGIN internal.pinerolo.linux.it.

proxy IN A 10.151.44.254
ns IN CNAME proxy.internal.pinerolo.linux.it.
  • /etc/bind/db.archive.ubuntu.com
; BIND db file for archive.ubuntu.com

$TTL 86400

@ IN SOA proxy.internal.pinerolo.linux.it. info.pinerolo.linux.it. (
2009101001  ; serial number YYMMDDNN
28800  ; Refresh
7200  ; Retry
864000  ; Expire
86400  ; Min TTL
)

NS proxy.internal.pinerolo.linux.it.


$ORIGIN archive.ubuntu.com.

* IN A 10.151.44.254
  • /etc/bind/db.security.ubuntu.com
; BIND db file for archive.ubuntu.com

$TTL 86400

@ IN SOA proxy.internal.pinerolo.linux.it. info.pinerolo.linux.it. (
2009101802  ; serial number YYMMDDNN
28800  ; Refresh
7200  ; Retry
864000  ; Expire
86400  ; Min TTL
)

NS proxy.internal.pinerolo.linux.it.

security.ubuntu.com. IN A 10.151.44.254
  • /etc/bind/db.packages.medibuntu.org
; BIND db file for archive.ubuntu.com

$TTL 86400

@ IN SOA proxy.internal.pinerolo.linux.it. info.pinerolo.linux.it. (
2009101001  ; serial number YYMMDDNN
28800  ; Refresh
7200  ; Retry
864000  ; Expire
86400  ; Min TTL
)

NS proxy.internal.pinerolo.linux.it.

packages.medibuntu.org. IN A 10.151.44.254

Non resta che far rileggere a Bind i suoi files di configurazione

# killall -1 named

(nel caso in cui killall non sia installato lo potete installare con il pacchetto psmisc oppure potete semplicemente fare un restart del servizio Bind)

Apache 2

Il contenuto del mirror deve essere pubblicato attraverso il protocollo http e per fare questo ho scelto Apache 2. L'installazione non nasconde sorprese:

# apt-get install apache2

Quanto alla configurazione, ho creato due VirtualHost, uno per il mirror di Ubuntu, l'altro per il mirror di Medibuntu. Ovviamente potete crearne quanti volete, in base a quanti mirror avete. Riporto qui il file di configurazione /etc/apache2/sites-available/default:

    ServerAdmin webmaster@localhost

Ho poi creato il file /etc/apache2/sites-available/medibuntu cambiando, rispetto al precedente, solo il ServerName, la DocumentRoot e la Directory dei pacchetti, in modo da puntare a dove tengo il mirror di medibuntu. Mentre il sito "default" è attivo da subito, il sito "medibuntu" deve essere attivato una tantum con il comando:

# a2ensite medibuntu

Il server DHCP

Sulla scheda LAN dobbiamo fornire servizio DHCP in modo che i computer in rete possano configurarsi automaticamente la rete senza dover specificare nulla a mano. Installiamo prima di tutto il server DHCP

# apt-get install dhcp3-server

poi andiamo a definire una sottorete compatibile con la configurazione dell'interfaccia LAN fatta prima. Nel file

/etc/dhcp3/dhcpd.conf 

inseriamo queste righe:

authoritative;

subnet 10.151.44.0 netmask 255.255.255.0 {
range 10.151.44.100 10.151.44.253;
option domain-name-servers 10.151.44.254;
option domain-name "internal.pinerolo.linux.it";
option routers 10.151.44.254;
}

In questo modo gli indirizzi di rete locale dal 10.151.44.100 al 10.151.44.253 saranno gestiti dal DHCP, mentre quelli con finale inferiore a 100 potremo usarli noi per installare eventuali altri server o access point o stampanti che dovessero necessitare di un indirizzo ip statico.

Ci resta solo da dire al server DHCP su quale scheda di rete deve mettersi in ascolto. Modifichiamo il file

/etc/default/dhcp3-server

ed assicuriamoci che la riga che inizia con INTERFACES sia fatta così

INTERFACES="lan"

Fatto questo riavviamo il server DHCP:

# /etc/init.d/dhcp3-server restart

Il proxy SQUID

Dopo aver installato Squid

# apt-get install squid

modifichiamo il suo file di configurazione

# nano /etc/squid/squid.conf

Questo è un file molto lungo, ma le modifiche che dobbiamo apportare sono poche, in proporzione alle opzioni disponibili. Cerchiamo la riga fatta così (nel mio file di configurazione è la riga numero millecentoundici, ma la posizione potrebbe cambiare un po' nel vostro):

# Squid normally listens to port 3128

e facciamo in modo che la riga subito sotto questa (la 1112 nel mio caso) contenga

http_port 10.151.44.254:3128 transparent

Questo dice a Squid di comportarsi come proxy trasparente, ovvero di funzionare correttamente anche se i vari browser della rete locale non sono stati configurati per usare un proxy. Poi andiamo a concedere l'accesso al proxy da parte di chiunque, tanto per non doverci smazzare problemi di accesso che vista la natura itinerante del proxy non avrebbero ragione di esistere. Cerchiamo la riga che dice

http_access deny all

(nel mio caso è la riga numero 680) e facciamola diventare

http_access allow all

Ora diciamo a Squid quale DNS usare al posto di quello fornito dal router collegato alla scheda WAN e gli diciamo di usare il Bind installato prima su questo stesso PC. Questo serve a fare in modo che, se qualche browser viene configurato per usare il proxy esplicitamente e quindi demanda al proxy la risoluzione dei nomi, anche il proxy usi il mirror locale invece dei mirror ufficiali di Ubuntu. Aggiungiamo questa riga:

dns_nameservers 10.151.44.254

(nel mio caso la posizione ideale è intorno alla riga 4561). È arrivato il momento di dire in quale directory vogliamo che squid tenga le copie delle pagine internet. Cerchiamo la riga che imposta la cache_dir (nel mio caso è la riga 1941) e facciamo in modo che contenga:

cache_dir aufs /cache/squid 20000 64 256

dove 20000 significa 20 giga di limite. Potete modificare questo valore a piacimento. Ovviamente bisognerà creare la directory /cache/squid ed assicurarsi che su disco ci sia spazio a sufficienza in base al valore impostato (in particolare ne serve il 50% in più, nel mio caso quindi 30 giga).

Infine può tornare utile tenere sul proxy una copia di eventuali file grandi scaricati da internet. Cerchiamo la prima riga che definisce un refresh_pattern (nel mio caso è la riga 2738) e appena prima di quella inseriamo

refresh_pattern \.rpm$          1440    100%    28800 ignore-reload ignore-no-cache

In questo modo non avremo un mirror anche per Fedora e altre distro che usano il formato rpm, ma almeno i pacchetti di queste distro andranno scaricati una sola volta durante il Linux Day, perché la seconda si troveranno già nella cache di Squid. Ovviamente possiamo aggiungere altre righe simili per altri nomi di file come .zip o .tgz. Quanto ai file .deb bisogna prestare un po' di attenzione, perché se si inserisse una riga del genere anche per loro finiremmo con l'avere due copie di tali files sull'hard disk del proxy, una nella directory del mirror e l'altra nella cache di squid. È certamente possibile specificare un refresh_pattern per i files .deb che mantenga solo i files non scaricati dai mirror di Ubuntu o Medibuntu (quindi non dal mirror locale), però personalmente ho preferito fregarmente e tenere in cache pure loro, tanto la conseguenza peggiore è lo spreco di spazio su disco che nel mio caso non mancava.

iptables

In ultimo dobbiamo configurare il routing. Iniziamo col dire a Linux che deve far passare i pacchetti da una scheda di rete all'altra, quindi apriamo il file

/etc/sysctl.conf

e assicuriamoci che ci sia una riga fatta così, senza # davanti (se non c'è aggiungiamola)

net.ipv4.ip_forward=1

Salviamo il file e rendiamo attive le modifiche con

# sysctl -p

Ora dobbiamo dire al kernel in base a quali regole i pacchetti devono passare da una scheda all'altra:

# iptables -t nat -A POSTROUTING -o wan -j MASQUERADE

In ultimo dobbiamo fare in modo che le richieste HTTP (pagine internet) vadano al proxy Squid invece che direttamente su internet:

# iptables -t nat -A PREROUTING -s ! 127.0.0.0/24 -d ! 10.151.44.254/32 -i ! wan -p tcp -m tcp --dport 80 \
-j DNAT --to-destination 10.151.44.254:3128

Le impostazioni di iptables vengono perse appena si spegne il PC, quindi dobbiamo salvarle in un file e ricaricarle ogni volta che il nostro proxy si accende. Per salvarle scriviamo:

# iptables-save > /etc/iptables.conf

Per ricaricarle all'avvio il modo più elegante è creare uno script

/etc/network/if-up.d/iptables

contenente solo il comando di ripristino delle regole

#!/bin/bash

/sbin/iptables-restore < /etc/iptables.conf

Non dimentichiamoci di dare il permesso di esecuzione a questo nuovo script:

# chmod a+x /etc/network/if-up.d/iptables

Facciamo un reboot per verificare che il proxy funzioni, che configuri correttamente la rete, che faccia partire gli aggiornamenti dei mirror, etc... non guasta provare ad attaccare uno switch alla scheda LAN e provare a fare l'installazione di un Ubuntu su un PC attaccato a questo switch. Nel mio caso lo scaricamento dei pacchetti avveniva a circa 11 megabyte al secondo, ovvero circa il limite teorico della rete LAN a 100 megabit.