english
NebuLog

Pagine di manutenzione con Apache e Capistrano

di Alberto Vena
Topics: Systems

Maintenace_blog Certe volte la nostra applicazione deve rimanere offline per motivi di manutenzione, alcune volte per pochi secondi, altre volte per molto più tempo. In ogni caso è sempre bene mostrare una pagina di manutenzione per diversi motivi:

  • si avvisano gli utenti del disagio magari indicando anche la data e l'ora della fine dell'intervento;
  • si informano i motori di ricerca di non indicizzae le pagine nei momenti in cui il sito è giù ritornando lo status code 503 (Service Temporarily Unavailable);
  • si evita che l'accesso di qualche utente durante una modifica importante possa creare danni o inutili eccezioni.

Configurare Apache

La prima cosa da fare è configurare Apache in modo tale che mostri la pagina di manutenzione per qualsiasi richiesta arrivi al server. Per evitare di modificare la configurazione di apache ogni volta che vogliamo disabilitare il sito scriviamo anche una condizione che forzi apache a mostrare la pagina di manutenzione solo nel caso in cui questa sia presente sul server.

Ecco il codice da inserire nel nostro Virtual Host (solitamente in /etc/apache2/site-enabled/000-default)

<VirtualHost *:80>
  ...

  RewriteEngine On

  # Show maintenance page if it exists
  ErrorDocument 503 /system/maintenance.html
  RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|png)$
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$  -  [redirect=503,last]

  ...
</VirtualHost>

ricarichiamo la nuova configurazione di apache affinché le modifiche abbiamo effetto:

$ sudo service apache2 reload

Ora, se creiamo il file /system/maintenance.html sul server, ogni richiesta verrà redirezionata su questo rispondendo con lo status code 503. Eliminando il file il sito ritornerà a funzionare correttamente.

Nota 1: La prima condizione:

RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|png)$

fa in modo che le richieste fatte per fogli di stile e immagini non vengano redirezionate; questo permette di includere queste risorse nella pagina di manutenzione.

Nota 2: mod_rewrite deve essere stato attivato su Apache. Se non lo è lanciate il comando:

$ sudo a2enmod rewrite

Disabilitare il sito con Capistrano

Inserire manualmente questo file sul server ogni volta che effettuiamo un operazione di manutenzione può essere un operazione alquanto noiosa. È qui che entra in gioco Capistrano con un task creato appositamente per questa esigenza:

$ cap deploy:web:disable

Questo task non fa altro che creare un file html in locale e spostarlo per noi sul server. Volendo si possono anche passare degli argomenti al task in modo da visualizzare nel testo del file il motivo dell'intervento e quando il sito tornerà a funzionare. Ad esempio lanciando il task con questi parametri

$ cap deploy:web:disable \\
              REASON="database upgrade" \\
              UNTIL="14:00 MST"

otterremo il seguente risultato:

Stmaintenance

Questo è il link alla pagina di manutenzione creata da Capistrano di default.

Personalizzare la pagina di manutenzione di Capistrano

Non si può negare che la pagina di default creata da Capistrano sia tanto comoda quanto "semplice". Se si hanno esigenze grafiche particolari, l'unico modo per personalizzare la pagina è sovrascrivere il task deploy:web:disable, indicando dove andare a prendere la nostra pagina.

Ecco un esempio per chi usa template erb (default in Ruby on Rails):

namespace :deploy do
  namespace :web do
    desc <<-DESC
        Present a maintenance page to visitors. Disables your application's web \
        interface by writing a "#{maintenance_basename}.html" file to each web server. The \
        servers must be configured to detect the presence of this file, and if \
        it is present, always display it instead of performing the request.

        Customized task allow us to render erb file. Usage:

        $ cap deploy:web:disable \\
                REASON="hardware upgrade" \\
                UNTIL="12pm Central Time"

    DESC
    task :disable, :roles => :app do

      on_rollback { rm "#{shared_path}/system/maintenance.html" }

      require 'erb'
      deadline, reason = ENV['UNTIL'], ENV['REASON']
      maintenance = ERB.new(File.read("./app/views/layouts/maintenance.html.erb")).result(binding)

      put maintenance, "#{shared_path}/system/maintenance.html", :mode => 0644
    end
  end
end

Non ci rimane che creare il file /app/views/layouts/maintenance.html.erb ricordandoci di stampare da qualche parte nel file le variabili passate. Ad esempio:

<p style="color: red; font-size: 16px; line-height: 20px;">
  The system is down for  <%= reason ? reason : "maintenance"%>
  as of <%= Time.now.strftime("%H:%M %Z") %>
</p>
<p style="color: #666;">
  It'll be back <%= deadline ? deadline : "shortly" %>
</p>

Abilitare la manutenzione durante il deploy

Si può anche abilitare automaticamente la modalità manutenzione durante ogni deploy. Per farlo basta aggiungere al file config/deploy.rb un paio di hook personalizzati:

before 'deploy:update_code', 'deploy:web:disable'
after 'deploy:restart', 'deploy:web:enable'

Altre risorse