Закрываем сайт на время обслуживания

Периодически возникает потребность закрыть сайт на время обновления/обслуживания и выдавать пользователям какую-нибудь заглушку. Чтобы они не пугались.

Потребность в специальной maintenance.html имеется только для крупных проектов, поэтому для этого блога такой странички нет.

А для моего сервиса http://fitlog.ru она выглядит как-то так.

Эта статья о том как сделать подобную страничку используя nginx и capistrano.

Принцип действия #

При выполнении команды выключения генерируется статическая страница maintenance.html.

При обнаружении этой странички Nginx по всем запросам показывает только её. При этом возвращает ошибку 503, чтобы поисковые боты не проиндексировали изменение содержимого.

После того, как необходимость в заглушке устранена она удаляется. И всё возвращается на круги своя.

Шаблон заглушки #

Начнём с создания самой странички:

vim app/views/layouts/maintenance.html.slim
- reason ||= "Обновление системы"
- line = "-" * (reason.length+3)

doctype html
html
  head
    title #{reason}
    link rel="icon" href="/favicon.png"
    link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css"
    css:
      * {margin: 0px; padding: 0px}
      body {
        font-size: 40px;
        background-color: #f0f0f0;
        font-family: Open Sans, Verdana, sans-serif;
      }
      div.outer{
          display:inline-block;
          position:relative;
          left:50%;
      }

      div.inner{
          position:relative;
          left:-50%;
      }
      pre {
        color: #4D3B3B;
      }
  body
    .outer
      .inner
        img src="/maintenance.jpg" alt=""
        pre # #{line}
            # #{reason}
            # #{line}

По желанию в шаблон можно добавить и другие переменные, например время выключения сервера и время включения:

с #{Time.now.strftime("%H:%M %Z")}
Сервер будет включен в #{deadline || 'ближайшее время'}

Рецепт Capistrano #

vim config/deploy.rb
namespace :deploy do
  # Unicorn
  ...

  # Maintenance
  namespace :web do
    task :disable, :roles => :web, :except => { :no_release => true } do
      require 'slim'
      on_rollback { run "rm #{shared_path}/system/maintenance.html" }

      reason = ENV['reason'] 

      template = File.read("./app/views/layouts/maintenance.html.slim")
      result = Slim::Template.new{template}.render(Object.new, :reason => reason)

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

    task :enable, :roles => :web, :except => { :no_release => true } do
      run "rm #{shared_path}/system/maintenance.html"
    end
  end
end

Виртуальный хост Nginx #

Задача отдавать заглушку на все запросы, кроме запросов статики (как минимум из-за favicon):

upstream fitlog {
  server unix:/data/projects/fitlog/shared/unicorn.sock fail_timeout=0;
}

server {
  listen www.fitlog.ru:80;
  server_name www.fitlog.ru;
  return 301 $scheme://fitlog.ru$request_uri;
}

server {
  listen fitlog.ru:80;
  server_name fitlog.ru;

  keepalive_timeout 5;
  client_max_body_size    50m;
  client_body_buffer_size 128k;

  root /data/projects/fitlog/current/public;

  error_log  /data/projects/fitlog/shared/log/nginx_error.log;
  access_log off;

  rewrite_log on;

  # Rails error pages
  error_page 500 502 504 /500.html;

  # Rails assets pipeline
  location ` ^/assets/ {
    gzip_static on; # to serve pre-gzipped version
    expires max;
    add_header Cache-Control public;
  }

  if (-f $document_root/system/maintenance.html) { return 503; }
        error_page 503 @maintenance;
        location @maintenance {

          if (-f $request_filename) { break; } 

          rewrite  ^(.*)$  /system/maintenance.html last;
          break;
        }


  location / { try_files $uri @unicorn; }

  location @unicorn {
    proxy_pass  http://fitlog;
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
  }
}

Использование #

Выключить сайт:

cap deploy:web:disable

Выключить с изменённой причиной

cap deploy:web:disable reason="Слабоумие и отвага"

Включить:

cap deploy:web:enable

Добавить комментарий