Блог Олега Сердюкова

Подключение SSL-сертификата COMODO

SSL-сертификат для блога покупал у ssl.com.ua. Я обычно не пользуюсь услугами локальных компаний из-за неоднократных проблем, которые мне они создавали (от качества сервиса до идиотской службы поддержки). Но этой компанией я доволен. Их я нашёл, когда года три назад мне был нужен сертификат для клиента, а у привычных зарубежных компаний (и даже при покупке напрямую у того же Symantec, Verisign, Comodo) они стоили неадекватно дорого. А здесь была и цена хорошая, и, как выяснилось, поддержка отличная.

Сейчас выбрал самый дешёвый сертификат COMODO Positive SSL:

При создании выбрал www.ctrld.me, это очевидный хинт, но однажды я промахнулся, заказав для клиента сертификат без www, и потом пришлось покупать новый за свои деньги (клиент бы вряд ли заметил проблему, но я так не могу, должно быть всё правильно). Почему с www? Потому что один сертификат покрывает и www.domain.name, и domain.name, и при форвардах https лучше иметь валидный сертификат.

Сайт мой личный, так что воспользовался генератором на ssl.com.ua для формирования CSR. В другом бы случае запрос формировал командой вида (не ручаюсь за правильность):

$ openssl req -nodes -newkey rsa:2048 -keyout /etc/ssl/private/www.ctrld.me.key -out /etc/ssl/private/www.ctrld.me.csr

На этой стадии у меня получились два файла - certificate signing request (csr) и приватный ключ (key):

  • /etc/ssl/private/www.ctrld.me.key
  • /etc/ssl/private/www.ctrld.me.csr

Оплатил сертификат в панели управления, загрузил csr и key. Дальше — проверка того, что я имею право управлять доменом. Выбрал подтверждение по email, который указан в whois. Вариант проверки — загрузка определённого файла на сайт.

Информация по email видна на whois .me. Домен перенёс когда-то на Amazon Route53 ($0.5 в месяц за зону и продление стоит адекватных денег, не помню точно сколько, но точно дешевле изначального imena.ua и надёжнее следующего моего регистратора NameCheap), а они используют Ghandi. Заодно у меня активен “Whois Protege” — защита персональных данных.

Domain Name: CTRLD.ME
Registrant Name: Oleg Serdyukov
Registrant Email: ba7xxx301603e723ad2bda4b3dd8b2698d-1959204@contact.gandi.net
Admin Email: feec02570xxx341691423ee07409a4cf-1959201@contact.gandi.net
Tech Email: f4c85958cb0xxxd5c4c94aaf4b907a5-1959207@contact.gandi.net

Кстати, imena.ua — один из примеров, почему я испытываю отвращение от местечковых контор. Эти клоуны не могли при обслуживании даже связать мою учётную запись в их системе с моим единственным доменом и требовали каждый раз его называть, а затем учили меня, как должна писаться моя фамилия и тупо не соглашались писать её так, как я хочу. Кроме того за продление .me они когда-то хотели $60 при $15 у NameCheap. Вечное желание на одном клиенте заработать столько, чтобы отбить свою норму прибыли 400%.

После получения пары писем с информированием и одного с URL от COMODO и подтверждением, что действительно могу управлять доменом, сертификат был выпущен. На весь процесс ушло минут 10.

По почте пришёл архив с ca-bundle (root and intermediate certificates) и сгенерированный сертификат crt. Я их переименовал в:

  • /etc/ssl/private/www.ctrld.me.ca-bundle
  • /etc/ssl/private/www.ctrld.me.crt

Использую nginx, ему нужен комбинированный сертификат:

$ sudo -i
$ cat /etc/ssl/private/www.ctrld.me.crt /etc/ssl/private/www.ctrld.me.ca-bundle > /etc/ssl/private/www.ctrld.me-ssl-bundle.crt

Ограничиваю права:

$ chown root /etc/ssl/private/www.ctrld.me{.csr,.key,.crt,.ca-bundle,-ssl-bundle.crt}
$ chmod 600 /etc/ssl/private/www.ctrld.me{.csr,.key,.crt,.ca-bundle,-ssl-bundle.crt}

Усиливаю безопасность использованием Diffie Hellman Ephemeral Parameters (вроде бы смотрел эту статью: “Strong SSL Security on nginx”):

$ openssl dhparam -out /etc/ssl/private/dhparam.pem 4096
$ chmod 600 /etc/ssl/private/dhparam.pem

Настраиваю SSL:

$ cat /etc/nginx/sites-available/ssl.ctrld.me
server {
    listen         443 ssl;
    server_name    ctrld.me;
    include        /etc/nginx/sites-available/template-ssl.ctrld.me;
    access_log     /var/log/nginx/ssl.ctrld.me.access.log;
    include        /etc/nginx/sites-available/template-ctrld.me;
}

server {
    listen         443 ssl;
    server_name    www.ctrld.me;
    include        /etc/nginx/sites-available/template-ssl.ctrld.me;
    rewrite        ^(.*) https://ctrld.me$1 permanent;
    access_log     /var/log/nginx/ssl.www.ctrld.me.access.log;
}

$ cat /etc/nginx/sites-available/template-ssl.ctrld.me
ssl                         on;
ssl_certificate             /etc/ssl/private/www.ctrld.me-ssl-bundle.crt;
ssl_certificate_key         /etc/ssl/private/www.ctrld.me.key;
ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers                 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers   on;
ssl_session_cache           shared:SSL:10m;
ssl_session_timeout         15m;
#add_header                  Strict-Transport-Security "max-age=16070400; includeSubdomains";
#add_header                  X-Frame-Options DENY;
ssl_dhparam                 /etc/ssl/private/dhparam.pem;
ssl_stapling                on;
ssl_stapling_verify         on;

На http-версии делаю редиректы:

$ cat /etc/nginx/sites-available/ctrld.me
server {
    listen 80;
    server_name ctrld.me;
    access_log  /var/log/nginx/ctrld.me.access.log;
    rewrite ^(.*) https://ctrld.me$1 permanent;
}

server {
    listen 80;
    server_name www.ctrld.me;
    rewrite ^(.*) https://ctrld.me$1 permanent;
    access_log  /var/log/nginx/www.ctrld.me.access.log;
}

Для IPv6 не делаю SSL, руки не дошли проверять:

$ cat /etc/nginx/sites-available/ipv6.ctrld.me
server {
    listen [::]:80;
    server_name ctrld.me;
    access_log  /var/log/nginx/ipv6.ctrld.me.access.log;
    include /etc/nginx/sites-available/template-ctrld.me;
}

server {
    listen [::]:80;
    server_name www.ctrld.me;
    rewrite ^(.*) http://ctrld.me$1 permanent;
    access_log  /var/log/nginx/ipv6.www.ctrld.me.access.log;
}

Темплейты:

$ cat /etc/nginx/sites-available/template-ctrld.me
error_page 404 /404.html;

index index.html;
autoindex off;

etag on;

root /srv/ctrld.me;

# Deny illegal Host headers
if ($host !~* ^ctrld.me$ ) {
    return 444;
}

location ~* ^(/atom.xml|/feed|/feed/)$ {
set $feed_redirect 'http://feeds.feedburner.com/theapplegeekru';
    if ($http_user_agent !~ (FeedValidator|FeedPress|FeedBurner)){
        rewrite ^ $feed_redirect permanent;
    }
    break;
}

### Common deny, drop, or internal locations
location ~ /\. { access_log off; log_not_found off; deny all; }
location ~ ~$ { access_log off; log_not_found off; deny all; }
location = /robots.txt { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }

### Rewrite legacy links from theapplegeek.ru
if ($new) {
    return 301 $new;
}

### Common root location
location / {
    try_files $uri $uri/ =404;
}

### Set up some basic caching rules to lower your traffic. Most common files
### like images, sound and movies are cached for 30 days.
#location ~* \.(ico|gif|jpeg|jpg|png|flv|pdf|swf|mov|mp3|wmv|ppt)$ {
#    expires                 30d;
#    add_header              Cache-Control  "public";
#}

### Static content files like HTML, CSS and Javascript is cached for 3 days
### but must be revalidated.
location ~* \.(js|css|woff)$ {
    expires                 14d;
    add_header              Pragma public;
    add_header              Cache-Control  "private, must-revalidate, proxy-revalidate";
}

Я ещё использую редирект для старых ссылок, тянущихся из Wordpress theapplegeek.ru:

$ cat /etc/nginx/conf.d/maps.conf
map $uri $new {
    include /etc/nginx/ctrld.me.map;
}

$ head /etc/nginx/ctrld.me.map
/archives/1         /blog/2009/08/20/hello-world/;
/archives/1004      /blog/2009/10/13/ustanovka-usb-modema-3g-huawei-e219-pod-snow-leopard/;
/archives/1011      /blog/2009/10/14/ustanovka-paketov-unix-macports/;
/archives/1026      /blog/2009/10/15/rabota-s-polzovatelskimi-nastrojkami-iz-konsoli-defaults/;
/archives/103       /blog/2009/09/06/nemnogo-sozercaniya/;
/archives/1036      /blog/2009/10/16/kombinacii-klavish-dejstvuyushhie-pri-zagruzke-intel-mac/;
/archives/1045      /blog/2009/10/15/software-updates/;
/archives/1064      /blog/2009/10/16/izuchaem-klaviaturnye-kombinacii-keycue/;
/archives/1067      /blog/2009/10/16/otklyuchenie-buferizacii-v-shell/;
/archives/1075      /blog/2009/10/18/o-bloge/;

Приведу уже полный конфиг:

$ cat /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 768;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    charset                     utf-8;
    source_charset              utf-8;

    server_names_hash_max_size  2048;
    server_names_hash_bucket_size   128;
    map_hash_bucket_size        128;
    map_hash_max_size       2048;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ## Compression
    gzip                        on;
    gzip_static                 on;
    gzip_buffers                32 8k;
    gzip_comp_level             3;
    gzip_http_version           1.0;
    gzip_min_length             0;
    # text/html comressed always
    gzip_types                  text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
    gzip_vary                   on;
    gzip_proxied                any;
    #gzip_proxied               expired no-cache no-store private auth;
    gzip_disable                "MSIE [1-6]\.(?!.*SV1)";

    ##
    # Virtual Host Configs
    ##

    ## Deny access to any host
    server {
      server_name  _;  #default
      return 444;
    }
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Активирую сайты:

$ ln -s /etc/nginx/sites-available/ssl.ctrld.me /etc/nginx/sites-enabled/
$ ln -s /etc/nginx/sites-available/ctrld.me /etc/nginx/sites-enabled/
$ ln -s /etc/nginx/sites-available/ipv6.ctrld.me /etc/nginx/sites-enabled/

Проверяю конфигурацию и перезапускаю nginx:

$ service nginx configtest
$ service nginx restart
$ service nginx status

Проверяю, правильно ли работает SSL:

$ openssl s_client -connect ctrld.me:443 -tls1 -tlsextdebug -status

Открываю в браузере:

Анализирую сайт SSL-тестером и получаю “Overall Rating A”:

Особенности:

  • картинки раньше у меня были на cdn.ctrld.me. Если на странице https есть элементы, загружаемые по http, то страница не показывается, как “защищённая” (например, в Safari нет значка замка). Покупать сертификат и для этого домена не хотелось, трафик у меня небольшой, поэтому вернул все картинки в иерархию блога без отдельного поддомена.
  • код disqus был старый, не ориентированный на http/https и js не загружадся, пришлось актуализировать
  • пришлось мигрировать комментарии в Disqus
  • в pr-cy.ru видно падение по некоторым параметрам, так как ссылки были на http, а я поставил https. Мне это безразлично
  • вроде бы поле Refererrs не передаётся в большинстве случаев, но и это мне не существенно
  • зашёл в магазин и попробовал открыть сайт на телефоне с неактуальной версией iOS, но в пределах 9-й, Safari стал ругаться на неправильный сертификат. А это уже тревожный знак. Но если проигнорировать предупреждение, то зайти можно.

В общем пусть блог поработает на SSL. Посмотрю, какие ещё будут проблемы.

Comments