Rails 4 : exécuter une application dans un sous-répertoire avec Nginx

Cet article détaille la configuration Nginx et Rails pour faire tourner une application Rails dans un sous-répertoire.

Contexte

On ne va pas discuter ici si nous utilisons la meilleure architecture pour ce cas de figure mais  comment configurer un environnement existant pour faire fonctionner notre application dans un sous-répertoire.

L’application utilise Rails 4 et est servie par thin.

  • L’ancienne url de l’application : http://www.mydomain.com
  • La nouvelle url de l’application : http://www.mydomain.com/fr
  • Nginx écoute sur le port 80 et sert de reverse proxy vers un cluster thin qui sert l’application Rails

Configuration de Rails

config.ru

  • config.ru avant
# This file is used by Rack-based servers to start the application.

require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
  • config.ru après
map MyApp::Application.config.relative_url_root || "/" do
    run Rails.application
end

config/application.rb

Pour servir votre application dans un sous-répertoire, il faut utiliser l’option relative_url_root.

Cette option se change dans le fichier config/application.rb

config.relative_url_root = "/fr"

Configuration de Nginx

La configuration a été modifiée pour changer le « location / » en « location /fr ».

Nous avons rajouté un règle de réécriture pour gérer les assets rails qui sont servis directement par Nginx.

  • La configuration de notre vhost nginx
upstream thin_cluster {
    server unix:/var/www/myapp/shared/tmp/sockets/thin.0.sock;
    server unix:/var/www/myapp/shared/tmp/sockets/thin.1.sock;
}

server {
    listen 80;
    server_name  www.mydomain.com

    root /var/www/myapp/current/public;
    index.html;

    location ~ ^/fr/assets/  {
            rewrite ^/fr(.*)$ $1 last;
    }

    location /fr {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host:$server_port;
        proxy_redirect off;

        if (-f $request_filename/index.html) {
            rewrite (.*) $1/index.html break;
        }

        if (-f $request_filename.html) {
            rewrite (.*) $1.html break;
        }

        if (!-f $request_filename) {
            proxy_pass http://thin_cluster;
            break;
        }
    }
}

 

 

Restriction d’accès par IP ou password avec Nginx

Cet article vous montre comment configurer la restriction d’accès à votre serveur web Nginx à une ou plusieurs adresses IP de votre choix.

Configuration de la restriction d’accès

La configuration du site par défaut se trouve dans /etc/nginx/sites-available/default

La section qui nous intéresse est le location

location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
 }

Il faut ajouter les règles d’accès. Ici on autorise une adresse IP et on exclut tout le reste.

location / {
    # bureau
    allow 2a01:xxxx:51e:xxxx:14d:xxxx:9146:xxxx;
    # Deny the rest of the world
    deny all;

    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
 }

Test de la configuration Nginx

Avant d’activer une nouvelle configuration, il est toujours utile de bien s’assurer que la configuration est correcte et qu’il n’y a pas d’erreur de syntaxe dans le fichier.

Pour effectuer ce test, il faut utiliser le paramètre configtest avec le script de démarrage :

$ /etc/init.d/nginx configtest
* Testing nginx configuration
...done.

Si vous avez une erreur dans votre fichier de configuration, comme par exemple un ‘;’ oublié, le test va vous l’indiquer de la façon suivante :

$ /etc/init.d/nginx configtest
 * Testing nginx configuration
   ...fail!

Vérifiez les logs pour obtenir un message plus explicite :

$ tail /var/log/nginx/error.log
 [...]
 2016/11/22 10:39:05 [emerg] 14733#14733: invalid number of arguments in "allow" directive in /etc/nginx/sites-enabled/default:47

 

Recharger la configuration Nginx :

$ /etc/init.d/nginx reload

Vous pouvez aussi recharger la configuration avec le binaire Nginx :

$ nginx -s reload

Vous pouvez vérifier dans les logs Nginx que la configuration a bien été rechargée :

$ tail /var/log/nginx/error.log
[...]
2016/11/22 10:32:32 [notice] 14665#14665: signal process started

Test de la restriction d’accès

On peut tester la configuration depuis une IP externe :

$ curl -I http://vm.domain.com/
HTTP/1.1 403 Forbidden
Server: nginx/1.10.0 (Ubuntu)
Date: Tue, 22 Nov 2016 09:12:41 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive

Restriction d’accès par mot de passe

Pour créer un fichier de mot passe au format utilisé par Apache, vous pouvez utiliser la commande openssl :

$ printf "USER:$(openssl passwd -crypt)\n" >> .htpasswd

La fonction -crypt limite les mots de passe à 8 caractères

Pour des mots de passe plus long, utilisez la fonction -apr1

$ printf "USER:$(openssl passwd -apr1)\n" >> .htpasswd

Les 2 commandes précédentes vont vous demander le mot de passe de manière interactive dans le terminal.
Pour scripter cette commande, vous pouvez indiquer directement le mot de passe :

$ printf "USER:$(openssl passwd -apr1 PASSWORD)\n" >> .htpasswd

Attention, en utilisant cette dernière commande, vous pouvez faire apparaitre votre mot de passe dans l’historique du shell.

Configuration de Nginx pour l’accès par mot de passe

Il faut modifier votre section « location » pour indiquer à Nginx d’utiliser un fichier d’authentification:

location / {
    satisfy any;
    deny all;

    auth_basic "private";
    auth_basic_user_file /var/www/.htpasswd;

    try_files $uri $uri/ =404;
}

Configurer Nginx pour restreindre l’accès par IP ou par mot de passe

Dans cette configuration vous pouvez whitelister une ou plusieurs adresses IP et quand même laisser la possibilité de se connecter via un mot de passe si vous n’avez pas d’IP fixe.

location / {
    satisfy any;
    allow 111.222.333.444;
    deny all;

    auth_basic "private";
    auth_basic_user_file /var/www/.htpasswd;

    try_files $uri $uri/ =404;
}

Nginx: redirections en masse

Lors de la migration d’un blog, j’ai eu besoin de gérer des redirections permanentes (301) pour un grand nombre d’urls, entre 600 et 700 pour être précis. Malheureusement ces redirections ne peuvent être factorisées avec des patterns, ce sont que des urls uniques.

Pour ne pas charger la configuration de votre vhost dans nginx, vous pouvez utiliser le mot clé include pour stocker vos redirections dans un fichier à part.

Dans mon cas, la configuration nginx ressemble alors à ça :

  • /etc/nginx/site-enabled/v3.conf
server {
    listen 443 ssl;
    [...]
    include /etc/nginx/conf.d/v3.redirects
    [...]
    location / {
    [...]
    }
}

 

  • /etc/nginx/conf.d/v3.redirects
[...]
rewrite ^/le-stress(.*) /conseils/relaxation/le-stress$1 permanent;
[...]

Le fichier v3.redirects a été généré avec un script, il fait 625 lignes.

Cela fonctionne très bien pour un nombre limité de redirects. Si vraiment vous deviez gérer un nombre important de redirections, regardez du côté de lua et redis.

 

Nginx: redirection permanente

Vous pouvez avoir besoin de configurer une redirection permanente avec nginx pour forcer un domaine sur le www ou sur le https.

Configuration nginx

Par exemple pour forcer une redirection vers https pour le domaine cuisinez.info, la configuration nginx s’effectue alors comme suit :

server {
    server_name cuisinez.info;
    rewrite ^(.*)$ https://www.cuisinez.info$1 permanent;
}

server {
    server_name www.cuisinez.info;
    rewrite ^(.*)$ https://www.cuisinez.info$1 permanent;
}

Test du résultat avec curl :

$ curl -I http://www.cuisinez.info
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Tue, 10 May 2016 07:41:48 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Keep-Alive: timeout=20
Location: https://www.cuisinez.info/