
Dans un article précédent , la conception de la plate-forme logicielle NAS a été décrite.
Il est temps de le mettre en œuvre.
Vérifier
Assurez-vous de vérifier la santé de la piscine avant de commencer:
zpool status -v
Le pool et tous les disques qu'il contient doivent ĂŞtre EN LIGNE.
De plus, je suppose qu'à l'étape précédente, tout a été fait selon les instructions , et cela fonctionne, ou vous-même comprenez bien ce que vous faites.
Commodités
Tout d'abord, cela vaut la peine de prendre soin d'une gestion pratique si vous ne l'avez pas fait dès le début.
Il faudra:
- Serveur SSH:
apt-get install openssh-server
. Si vous ne savez pas comment configurer SSH, faire NAS sur Linux est trop tôt Vous pouvez lire les caractéristiques de son utilisation dans cet article , puis utiliser l' un des manuels . - tmux ou écran :
apt-get install tmux
. Pour enregistrer la session lors de la connexion via SSH et utiliser plusieurs fenĂŞtres.
Après avoir installé SSH, vous devez ajouter un utilisateur afin de ne pas vous connecter via SSH en tant que root (l'entrée est désactivée par défaut et vous n'avez pas besoin de l'activer):
zfs create rpool/home/user adduser user cp -a /etc/skel/.[!.]* /home/user chown -R user:user /home/user
Pour l'administration Ă distance, c'est un minimum suffisant.
Néanmoins, alors que vous devez garder le clavier et le moniteur connectés, comme vous devrez également redémarrer lors de la mise à jour du noyau et afin de vous assurer que tout fonctionne immédiatement après le chargement.
Une alternative consiste à utiliser Virtual KVM, qui fournit IME . Il y a une console là -bas, bien que dans mon cas, elle soit implémentée comme une applet Java, ce qui n'est pas très pratique.
Personnalisation
Préparation du cache
Pour autant que vous vous en souvenez, dans la configuration décrite par moi, il y a un SSD séparé sous L2ARC, qui n'est pas encore utilisé, mais pris "pour la croissance".
Facultatif, mais il est conseillé de remplir ce SSD avec des données aléatoires (dans le cas de Samsung EVO, il sera toujours rempli de zéros après l'exécution de blkdiscard, mais pas sur tous les SSD comme celui-ci):
dd if=/dev/urandom of=/dev/disk/by-id/ata-Samsung_SSD_850_EVO bs=4M && blkdiscard /dev/disk/by-id/ata-Samsung_SSD_850_EVO
Désactiver la compression des journaux
Sur ZFS, la compression est déjà utilisée, car la compression des journaux via gzip sera clairement superflue.
Désactiver:
for file in /etc/logrotate.d/* ; do if grep -Eq "(^|[^#y])compress" "$file" ; then sed -i -r "s/(^|[^#y])(compress)/\1#\2/" "$file" fi done
Mise à jour du système
Ici, tout est simple:
apt-get dist-upgrade --yes reboot
Création d'un instantané pour un nouvel état
Après le redémarrage, afin de corriger le nouvel état de fonctionnement, vous devez réécrire le premier instantané:
zfs destroy rpool/ROOT/debian@install zfs snapshot rpool/ROOT/debian@install
Organisation du système de fichiers
Partitionnement pour SLOG
La première chose à faire pour obtenir des performances ZFS normales est de mettre SLOG sur le SSD.
Permettez-moi de vous rappeler que SLOG dans la configuration utilisée est dupliqué sur deux SSD: pour cela, les périphériques sur LUKS-XTS seront créés en haut de la 4ème section de chaque SSD:
dd if=/dev/urandom of=/etc/keys/slog.key bs=1 count=4096 cryptsetup --verbose --cipher "aes-xts-plain64:sha512" --key-size 512 --key-file /etc/keys/slog.key luksFormat /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part4 cryptsetup --verbose --cipher "aes-xts-plain64:sha512" --key-size 512 --key-file /etc/keys/slog.key luksFormat /dev/disk/by-id/ata-Micron_1100-part4 echo "slog0_crypt1 /dev/disk/by-id/ata-Samsung_SSD_850_PRO-part4 /etc/keys/slog.key luks,discard" >> /etc/crypttab echo "slog0_crypt2 /dev/disk/by-id/ata-Micron_1100-part4 /etc/keys/slog.key luks,discard" >> /etc/crypttab
Partitionnement pour L2ARC et Swap
Vous devez d'abord créer des partitions sous swap et l2arc:
sgdisk -n1:0:48G -t1:8200 -c1:part_swap -n2::196G -t2:8200 -c2:part_l2arc /dev/disk/by-id/ata-Samsung_SSD_850_EVO
La partition de swap et L2ARC seront chiffrés sur une clé aléatoire, comme après un redémarrage, ils ne sont pas nécessaires et il est toujours possible de les recréer.
Par conséquent, dans crypttab, une ligne est écrite pour chiffrer / déchiffrer les partitions en mode clair:
echo swap_crypt /dev/disk/by-id/ata-Samsung_SSD_850_EVO-part1 /dev/urandom swap,cipher=aes-xts-plain64:sha512,size=512 >> /etc/crypttab echo l2arc_crypt /dev/disk/by-id/ata-Samsung_SSD_850_EVO-part2 /dev/urandom cipher=aes-xts-plain64:sha512,size=512 >> /etc/crypttab
Ensuite, vous devez redémarrer les démons et activer l'échange:
echo 'vm.swappiness = 10' >> /etc/sysctl.conf sysctl vm.swappiness=10 systemctl daemon-reload systemctl start systemd-cryptsetup@swap_crypt.service echo /dev/mapper/swap_crypt none swap sw,discard 0 0 >> /etc/fstab swapon -av
Parce que swapiness
n'est pas activement utilisé sur le SSD; le paramètre swapiness
, qui est 60 par défaut, doit être défini sur 10.
L2ARC n'est pas encore utilisé à ce stade, mais la section correspondante est déjà prête:
$ ls /dev/mapper/ control l2arc_crypt root_crypt1 root_crypt2 slog0_crypt1 slog0_crypt2 swap_crypt tank0_crypt0 tank0_crypt1 tank0_crypt2 tank0_crypt3
Réservoir de piscinesN
La création du pool tank0
sera décrite, tank1
est créé par analogie.
Afin de ne pas créer manuellement les mêmes partitions et d'éviter les erreurs, j'ai écrit un script pour créer des partitions chiffrées pour les pools:
Maintenant, en utilisant ce script, vous devez créer un pool pour stocker des données:
./create_crypt_pool.sh zpool create -o ashift=12 -O atime=off -O compression=lz4 -O normalization=formD tank0 raidz1 /dev/disk/by-id/dm-name-tank0_crypt*
Pour des notes sur le paramètre ashift=12
, voir mes articles précédents et commentaires à leur sujet.
Après avoir créé le pool, j'ai mis son journal sur le SSD:
zpool add tank0 log mirror /dev/disk/by-id/dm-name-slog0_crypt1 /dev/disk/by-id/dm-name-slog0_crypt2
À l'avenir, avec OMV installé et configuré, il sera possible de créer des pools via l'interface graphique:

Activation de l'importation de pool et des volumes de montage automatique au démarrage
Afin de garantir l'activation des pools de montage automatique, exécutez les commandes suivantes:
rm /etc/zfs/zpool.cache systemctl enable zfs-import-scan.service systemctl enable zfs-mount.service systemctl enable zfs-import-cache.service
À ce stade, la configuration du sous-système de disque est terminée.
Système d'exploitation
La première étape consiste à installer et configurer OMV afin d'obtenir enfin une sorte de fondation pour le NAS.
Installer OMV
OMV sera installé en tant que package deb. Pour ce faire, il est possible d'utiliser les instructions officielles .
Le script add_repo.sh
ajoute le référentiel OMV Arrakis à /etc/apt/ sources.list.d
afin que le système de traitement par lots voit le référentiel.
add_repo.sh cat <<EOF >> /etc/apt/sources.list.d/openmediavault.list deb http://packages.openmediavault.org/public arrakis main
Veuillez noter que par rapport à l'original, le référentiel partenaire est inclus.
Pour installer et initialiser, vous devez exécuter les commandes ci-dessous.
Commandes d'installation d'OMV. ./add_repo.sh export LANG=C export DEBIAN_FRONTEND=noninteractive export APT_LISTCHANGES_FRONTEND=none apt-get update apt-get --allow-unauthenticated install openmediavault-keyring apt-get update apt-get --yes --auto-remove --show-upgraded \ --allow-downgrades --allow-change-held-packages \ --no-install-recommends \ --option Dpkg::Options::="--force-confdef" \ --option DPkg::Options::="--force-confold" \ install postfix openmediavault
OMV installé. Il utilise son propre noyau, et après l'installation, un redémarrage peut être nécessaire.
Après le redémarrage, l'interface OpenMediaVault sera disponible sur le port 80 (accédez au navigateur du NAS par adresse IP):

Le nom d'utilisateur / mot de passe par défaut est admin/openmediavault
.
Configurer OMV
De plus, la majeure partie de la configuration passera par l'interface Web.
Établir une connexion sécurisée
Vous devez maintenant changer le mot de passe de l'administrateur WEB et générer un certificat pour le NAS afin de travailler sur HTTPS à l'avenir.
Le mot de passe est modifié dans l'onglet "Système-> Paramètres généraux-> Mot de passe administrateur Web" .
Pour générer un certificat sur l'onglet "Système-> Certificats-> SSL", sélectionnez "Ajouter-> Créer" .
Le certificat créé sera visible sur le même onglet:

Après avoir créé le certificat, dans l' onglet "Système-> Paramètres généraux", cochez la case "Activer SSL / TLS" .
Un certificat sera requis avant la fin de la configuration. La version finale utilisera un certificat signé pour contacter OMV.
Vous devez maintenant vous connecter à OMV, au port 443, ou simplement attribuer le préfixe https://
Ă IP dans le navigateur.
Si vous avez réussi à vous connecter, dans l'onglet "Système-> Paramètres généraux", vous devez activer la case à cocher "Forcer SSL / TLS".
Modifiez les ports 80 et 443 en 10080 et 10443 .
Et essayez de vous connecter Ă l'adresse suivante: https://IP_NAS:10443
.
La modification des ports est importante car les ports 80 et 443 utiliseront le conteneur Docker avec nginx-reverse-proxy.
Paramètres principaux
Les paramètres minimum qui doivent être effectués en premier:
- Dans l'onglet "Système-> Date et heure", vérifiez la valeur du fuseau horaire et définissez le serveur NTP.
- Dans l'onglet "Système-> Surveillance", activez la collecte des statistiques de performances.
- Sur l'onglet "Système-> Gestion de l'énergie", il vaut probablement la peine de désactiver la "Surveillance" pour qu'OMV n'essaye pas de contrôler les ventilateurs.
Réseau
Si la deuxième interface réseau NAS n'est pas encore connectée, connectez-la au routeur.
Ensuite:
- Dans l' onglet "Système-> Réseau", définissez le nom d'hôte sur "nas" (ou ce que vous voulez).
- Configurez la liaison pour les interfaces comme indiqué dans la figure ci-dessous: "Système-> Réseau-> Interfaces-> Ajouter-> Lien" .
- Ajoutez les règles de pare-feu nécessaires sur l'onglet "Système-> Réseau-> Pare-feu" . Tout d'abord, l'accès aux ports 10443, 10080, 443, 80, 22 pour SSH et l'autorisation de recevoir / envoyer ICMP sont suffisants.

En conséquence, les interfaces de liaison devraient apparaître, que le routeur verra comme une interface et lui attribuera une adresse IP:

Si vous le souhaitez, il est possible de configurer en plus SSH Ă partir de l'interface graphique Web:

Référentiels et modules
Dans l'onglet "Système-> Gestion des mises à jour-> Paramètres", activez "Mises à jour prises en charge par la communauté" .
Tout d'abord, ajoutez des référentiels OMV extras .
Cela peut être fait simplement en installant le plugin ou le package, comme indiqué sur le forum .
Sur la page "Système-> Plugins" vous devez trouver le plugin "openmediavault-omvextrasorg" et l'installer.
En conséquence, l'icône "OMV-Extras" apparaîtra dans le menu système (elle peut être vue dans les captures d'écran).
Allez-y et activez les référentiels suivants:
- OMV-Extras.org. Un référentiel stable contenant de nombreux plugins.
- Tests OMV-Extras.org. Certains plugins de ce référentiel ne sont pas dans le référentiel stable.
- Docker CE. En fait, Docker.
Dans l'onglet "System-> OMV Extras-> Kernel", vous pouvez sélectionner le noyau dont vous avez besoin, y compris le noyau de Proxmox (je ne l'ai pas installé moi-même, car je n'en ai pas encore besoin, donc je ne le recommande pas):

Installez les plugins nécessaires ( gras absolument nécessaire, en italique - facultatif, que je n'ai pas installé):
Liste des plugins.- openmediavault-apttool. GUI minimum pour travailler avec un système batch. Ajoute "Services-> Apttool" .
- openmediavault-anacron. Ajoute la possibilité de travailler à partir de l'interface graphique avec un planificateur asynchrone. Ajoute "Système-> Anacron" .
- openmediavault-backup. Fournit un système de sauvegarde dans le stockage. Ajoute une page "Système-> Sauvegarde" .
- openmediavault-diskstats. Nécessaire pour collecter des statistiques sur les performances du disque.
- openmediavault-dnsmasq . Vous permet d'augmenter le serveur DNS et DHCP sur le NAS. Parce que je le fais sur un routeur, je n'en ai pas besoin.
- openmediavault-docker-gui . Interface de gestion des conteneurs Docker. Ajoute "Services-> Docker" .
- openmediavault-ldap . Prise en charge de l'authentification via LDAP. Ajoute "Gestion des droits -> Service d'annuaire" .
- openmediavault-letsencrypt . Prise en charge de Let's Encrypt à partir de l'interface graphique. Il n'est pas nécessaire, car il utilise l'incorporation dans le conteneur nginx-reverse-proxy.
- openmediavault-luksencryption . Prise en charge du cryptage LUKS. Il est nécessaire que les disques chiffrés soient visibles dans l'interface OMV. Ajoute "Stockage-> Cryptage" .
- écrou openmediavault . Prise en charge UPS. Ajoute "Services-> UPS" .
- openmediavault-omvextrasorg . OMV Extras doit déjà être installé.
- openmediavault-resetperms. Vous permet de réinitialiser les autorisations et de réinitialiser les listes de contrôle d'accès sur les répertoires partagés. Ajoute "Contrôle d'accès -> Répertoires généraux -> Réinitialiser les autorisations" .
- openmediavault-route. Plugin utile pour la gestion du routage. Ajoute "Système-> Réseau-> Route statique" .
- openmediavault-symlinks. Offre la possibilité de créer des liens symboliques. Ajoute la page "Services-> Liens symboliques" .
- openmediavault-unionfilesystems. Prise en charge d'UnionFS. Cela peut ĂŞtre utile Ă l'avenir, bien que le docker utilise ZFS comme backend. Ajoute "Storage-> Union Filesystems" .
- openmediavault-virtualbox . Il peut être utilisé pour intégrer des capacités de gestion de machine virtuelle dans l'interface graphique.
- openmediavault-zfs . Le plugin ajoute le support ZFS à OpenMediaVault. Après l'installation, la page "Stockage-> ZFS" apparaîtra.
Disques
Tous les disques qui sont dans le système doivent être visibles OMV. Assurez-vous de cela en regardant l' onglet "Stockage-> Disques" . Si tous les disques ne sont pas visibles, lancez une analyse.

Là , sur tous les disques durs, la mise en cache d'écriture doit être activée (en cliquant sur un disque dans la liste et en cliquant sur le bouton "Modifier").
Assurez-vous que toutes les sections chiffrées sont visibles sur l' onglet "Stockage-> Chiffrement" :

Il est maintenant temps de configurer SMART, indiqué comme un moyen d'augmenter la fiabilité:
- Accédez à l' onglet "Stockage-> SMART-> Paramètres" . Allumez SMART.
- Au même endroit, sélectionnez les valeurs des niveaux de température des disques (critiques, généralement 60 C, et le régime de température optimal du disque 15-45 C).
- Accédez à l' onglet "Stockage-> SMART-> Appareils" . Activez la surveillance pour chaque lecteur.

- Accédez à l' onglet "Stockage-> SMART-> Tests planifiés" . Ajoutez un court auto-test une fois par jour pour chaque disque et un long auto-test une fois par mois. De plus, afin que les périodes d'auto-test ne se chevauchent pas.

Sur ce point, la configuration du disque peut être considérée comme terminée.
Systèmes de fichiers et répertoires partagés
Vous devez créer des systèmes de fichiers pour des répertoires prédéfinis.
Cela peut être fait depuis la console ou depuis l'interface WEB OMV ( Stockage-> ZFS-> Sélectionner le réservoir de la piscine0-> Bouton Ajouter -> Système de fichiers ).
Commandes de création de FS. zfs create -o utf8only=on -o normalization=formD -p tank0/user_data/books zfs create -o utf8only=on -o normalization=formD -p tank0/user_data/music zfs create -o utf8only=on -o normalization=formD -p tank0/user_data/pictures zfs create -o utf8only=on -o normalization=formD -p tank0/user_data/downloads zfs create -o compression=off -o utf8only=on -o normalization=formD -p tank0/user_data/videos
Le résultat doit être la structure de répertoires suivante:

Après cela, ajoutez les FS créés en tant que répertoires partagés sur la page "Gestion des droits d'accès-> Répertoires généraux-> Ajouter" .
Veuillez noter que le paramètre "Device" est égal au chemin d'accès au système de fichiers créé dans ZFS, et le paramètre "Path" pour tous les répertoires est "/".

Sauvegarde
La sauvegarde se fait par deux outils:
Si vous utilisez le plugin, vous obtenez très probablement une erreur:
lsblk: /dev/block/0:22: not a block device
Pour y remédier, comme l'ont noté les développeurs OMV dans cette "configuration très non standard", il serait possible de refuser le plugin et d'utiliser les outils ZFS sous forme d' zfs send/receive
.
Ou, spécifiez explicitement le paramètre «périphérique racine» sous la forme d'un périphérique physique à partir duquel le téléchargement est effectué.
Il est plus pratique pour moi d'utiliser le plugin et de sauvegarder le système d'exploitation à partir de l'interface, au lieu de cadrer quelque chose de moi-même avec zfs send, donc je préfère la deuxième option.

Pour que la sauvegarde fonctionne, créez d'abord le système de fichiers tank0/apps/backup
via ZFS, puis dans le menu "Système-> Sauvegarde", cliquez sur "+" dans le champ de paramètre "Dossier public" et ajoutez le périphérique créé comme cible et le champ "Chemin" réglé sur "/".
Il y a aussi des problèmes avec zfs-auto-snapshot. Si elle n'est pas configurée, elle prendra des photos toutes les heures, tous les jours, toutes les semaines, tous les mois pendant un an.
Le résultat est ce qui est dans la capture d'écran:

Si vous l'avez déjà rencontré, exécutez le code suivant pour supprimer les instantanés automatiques:
zfs list -t snapshot -o name -S creation | grep "@zfs-auto-snap" | tail -n +1500 | xargs -n 1 zfs destroy -vr
Configurez ensuite zfs-auto-snapshot pour qu'il s'exécute dans cron.
Pour commencer, supprimez simplement /etc/cron.hourly/zfs-auto-snapshot
si vous n'avez pas besoin de prendre des photos toutes les heures.
Notifications par e-mail
La notification par e-mail a été indiquée comme l'un des moyens d'assurer la fiabilité.
Par conséquent, vous devez maintenant configurer la notification par e-mail.
Pour ce faire, enregistrez une boîte sur l'un des serveurs publics (enfin, ou configurez le serveur SMTP vous-même, si vous avez vraiment des raisons de le faire).
Ensuite, vous devez vous rendre sur la page "Système-> Notification" et saisir:
- Adresse du serveur SMTP.
- Port du serveur SMTP.
- Identifiant
- Adresse de l'expéditeur (généralement, le premier composant de l'adresse correspond au nom).
- Mot de passe utilisateur
- Dans le champ "Destinataire", votre adresse habituelle Ă laquelle le NAS enverra des notifications.
Il est fortement conseillé d'activer SSL / TLS.
Un exemple de configuration pour Yandex est illustré dans la capture d'écran:

Configuration du réseau en dehors du NAS
Adresse IP
J'utilise une adresse IP statique blanche, qui coûte plus 100 roubles par mois. Si vous ne souhaitez pas payer et que votre adresse est dynamique, mais pas pour NAT, il est possible d'ajuster les enregistrements DNS externes via l'API du service sélectionné.
Néanmoins, il convient de garder à l'esprit qu'une adresse non NAT peut soudainement devenir une adresse NAT: en règle générale, les fournisseurs ne donnent aucune garantie.
Routeur
En tant que routeur, j'ai un Mikrotik RouterBoard , similaire Ă celui de l'image ci-dessous.

Trois choses sont requises sur le routeur:
- Configurez des adresses statiques pour le NAS. Dans mon cas, les adresses sont émises via DHCP, et je dois m'assurer que les adaptateurs avec une adresse MAC spécifique obtiennent toujours la même adresse IP. Dans RouterOS, cela se fait sur l' onglet "IP-> Serveur DHCP" avec le bouton "Rendre statique" .
- Configurez le serveur DNS afin que pour le nom "nas", ainsi que les noms se terminant par ".nas" et ".NAS.cloudns.cc" (où "NAS" est la zone sur ClouDNS ou un service similaire), il donne le système IP. Où faire cela dans RouterOS est indiqué dans la capture d'écran ci-dessous. Dans mon cas, cela est implémenté en faisant correspondre le nom avec une expression régulière: "
^.*\.nas$|^nas$|^.*\.NAS.cloudns.cc$
" - Configurez la redirection de port. Dans RouterOS, cela se fait sur l' onglet "IP-> Pare-feu" , je ne m'attarderai pas lĂ -dessus.

ClouDNS
CLouDNS est simple. Créez un compte, confirmez. Les enregistrements NS seront déjà enregistrés auprès de vous. Ensuite, une configuration minimale est requise.
Tout d'abord, vous devez créer les zones nécessaires (la zone portant le nom NAS surlignée en rouge dans la capture d'écran est ce que vous devez créer avec un nom différent, bien sûr).

Deuxièmement, dans cette zone, vous devez enregistrer les enregistrements A suivants:
- nas , www , omv , control et un nom vide . Pour accéder à l'interface OMV.
- ldap . Interface PhpLdapAdmin
- ssp . Interface pour changer les mots de passe des utilisateurs.
- test . Serveur de test.
Les noms de domaine restants seront ajoutés à mesure que les services seront ajoutés.
Cliquez sur la zone, puis sur "Ajouter un nouvel enregistrement" , sélectionnez le type A, entrez le nom de la zone et l'adresse IP du routeur derrière lequel se trouve le NAS.

Deuxièmement, vous devez accéder à l'API. Dans ClouDNS, il est payé, vous devez donc d'abord le payer. Dans d'autres services, c'est gratuit. Si vous savez ce qui est le mieux et que cela est pris en charge par Lexicon , veuillez écrire dans les commentaires.
Après avoir accédé à l'API, vous devez y ajouter un nouvel utilisateur d'API.

"IP address" IP : , API. , , API, auth-id auth-password . Lexicon, .

ClouDNS .
Docker
openmediavault-docker-gui, docker-ce .
, docker-compose , :
apt-get install docker-compose
:
zfs create -p /tank0/docker/services
, /var/lib/docker
. ( , SSD), , , .
..,
. .

, .
, GUI , : , .. , .
/var/lib
:
service docker stop zfs create -o com.sun:auto-snapshot=false -p /tank0/docker/lib rm -rf /var/lib/docker ln -s /tank0/docker/lib /var/lib/docker service docker start
:
$ ls -l /var/lib/docker lrwxrwxrwx 1 root root 17 Apr 7 12:35 /var/lib/docker -> /tank0/docker/lib
:
docker network create docker0
Docker .
nginx-reverse-proxy
Docker , .
, .
: nginx-proxy letsencrypt-dns .
, OMV 10080 10443, 80 443.
/tank0/docker/services/nginx-proxy/docker-compose.yml version: '2' networks: docker0: external: name: docker0 services: nginx-proxy: networks: - docker0 restart: always image: jwilder/nginx-proxy ports: - "80:80" - "443:443" volumes: - ./certs:/etc/nginx/certs:ro - ./vhost.d:/etc/nginx/vhost.d - ./html:/usr/share/nginx/html - /var/run/docker.sock:/tmp/docker.sock:ro - ./local-config:/etc/nginx/conf.d - ./nginx.tmpl:/app/nginx.tmpl labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" letsencrypt-dns: image: adferrand/letsencrypt-dns volumes: - ./certs/letsencrypt:/etc/letsencrypt environment: - "LETSENCRYPT_USER_MAIL=MAIL@MAIL.COM" - "LEXICON_PROVIDER=cloudns" - "LEXICON_OPTIONS=--delegated NAS.cloudns.cc" - "LEXICON_PROVIDER_OPTIONS=--auth-id=CLOUDNS_ID --auth-password=CLOUDNS_PASSWORD"
:
- nginx-reverse-proxy — c .
- letsencrypt-dns — ACME Let's Encrypt.
nginx-reverse-proxy jwilder/nginx-proxy .
docker0
— , , docker-compose.
nginx-proxy
— , . docker0. , 80 443 ports (, , docker0, ).
restart: always
, .
:
certs
/etc/nginx/certs
— , , Let's Encrypt. ACME ../vhost.d:/etc/nginx/vhost.d
— . ../html:/usr/share/nginx/html
— . ./var/run/docker.sock
, /tmp/docker.sock
— Docker . docker-gen ../local-config
, /etc/nginx/conf.d
— nginx. , ../nginx.tmpl
, /app/nginx.tmpl
— nginx, docker-gen .
letsencrypt-dns adferrand/letsencrypt-dns . ACME Lexicon, DNS .
certs/letsencrypt
/etc/letsencrypt
.
, :
LETSENCRYPT_USER_MAIL=MAIL@MAIL.COM
— Let's Encrypt. , .LEXICON_PROVIDER=cloudns
— Lexicon. — cloudns
.LEXICON_PROVIDER_OPTIONS=--auth-id=CLOUDNS_ID --auth-password=CLOUDNS_PASSWORD --delegated=NAS.cloudns.cc
— CLOUDNS_ID ClouDNS . CLOUDNS_PASSWORD — , API. NAS.cloudns.cc, NAS — DNS . cloudns , (cloudns.cc), ClouDNS API .
: .
, , , , Let's encrypt:
$ ls ./certs/letsencrypt/ accounts archive csr domains.conf keys live renewal renewal-hooks
, , .
/tank0/docker/services/nginx-proxy/nginx.tmpl {{ $CurrentContainer := where $ .Docker.CurrentContainerID | first }} {{ define }} {{ if .Address }} {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} {{ if and .Container.Node.ID .Address.HostPort }} # {{ .Container.Node.Name }}/{{ .Container.Name }} server {{ .Container.Node.Address.IP }}:{{ .Address.HostPort }}; {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} {{ else if .Network }} # {{ .Container.Name }} server {{ .Network.IP }}:{{ .Address.Port }}; {{ end }} {{ else if .Network }} # {{ .Container.Name }} {{ if .Network.IP }} server {{ .Network.IP }} down; {{ else }} server 127.0.0.1 down; {{ end }} {{ end }} {{ end }} # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server map $http_x_forwarded_proto $proxy_x_forwarded_proto { default $http_x_forwarded_proto; '' $scheme; } # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the # server port the client connected to map $http_x_forwarded_port $proxy_x_forwarded_port { default $http_x_forwarded_port; '' $server_port; } # If we receive Upgrade, set Connection to ; otherwise, delete any # Connection header that may have been passed to this server map $http_upgrade $proxy_connection { default upgrade; '' close; } # Apply fix for very long server names server_names_hash_bucket_size 128; # Default dhparam {{ if (exists ) }} ssl_dhparam /etc/nginx/dhparam/dhparam.pem; {{ end }} # Set appropriate X-Forwarded-Ssl header map $scheme $proxy_x_forwarded_ssl { default off; https on; } gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; log_format vhost '$host $remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log off; {{ if $.Env.RESOLVERS }} resolver {{ $.Env.RESOLVERS }}; {{ end }} {{ if (exists ) }} include /etc/nginx/proxy.conf; {{ else }} # HTTP 1.1 support proxy_http_version 1.1; proxy_buffering off; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ; {{ end }} {{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) ) }} server { server_name _; # This is just an invalid value which will never trigger on a real hostname. listen 80; {{ if $enable_ipv6 }} listen [::]:80; {{ end }} access_log /var/log/nginx/access.log vhost; return 503; } {{ if (and (exists ) (exists )) }} server { server_name _; # This is just an invalid value which will never trigger on a real hostname. listen 443 ssl http2; {{ if $enable_ipv6 }} listen [::]:443 ssl http2; {{ end }} access_log /var/log/nginx/access.log vhost; return 503; ssl_session_tickets off; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; } {{ end }} {{ range $host, $containers := groupByMulti $ }} {{ $host := trim $host }} {{ $is_regexp := hasPrefix $host }} {{ $upstream_name := when $is_regexp (sha1 $host) $host }} # {{ $host }} upstream {{ $upstream_name }} { {{ range $container := $containers }} {{ $addrLen := len $container.Addresses }} {{ range $knownNetwork := $CurrentContainer.Networks }} {{ range $containerNetwork := $container.Networks }} {{ if (and (ne $containerNetwork.Name ) (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name ))) }} ## Can be connected with network {{/* If only 1 port exposed, use that */}} {{ if eq $addrLen 1 }} {{ $address := index $container.Addresses 0 }} {{ template (dict $container $address $containerNetwork) }} {{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}} {{ else }} {{ $port := coalesce $container.Env.VIRTUAL_PORT }} {{ $address := where $container.Addresses $port | first }} {{ template (dict $container $address $containerNetwork) }} {{ end }} {{ else }} # Cannot connect to network of this container server 127.0.0.1 down; {{ end }} {{ end }} {{ end }} {{ end }} } {{ $default_host := or ($.Env.DEFAULT_HOST) }} {{ $default_server := index (dict $host $default_host ) $host }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to */}} {{ $proto := trim (or (first (groupByKeys $containers )) ) }} {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to */}} {{ $network_tag := or (first (groupByKeys $containers )) }} {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to */}} {{ $https_method := or (first (groupByKeys $containers )) }} {{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to */}} {{ $ssl_policy := or (first (groupByKeys $containers )) }} {{/* Get the HSTS defined by containers w/ the same vhost, falling back to */}} {{ $hsts := or (first (groupByKeys $containers )) }} {{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{ $vhost_root := or (first (groupByKeys $containers )) }} {{/* Get the first cert name defined by containers w/ the same vhost */}} {{ $certName := (first (groupByKeys $containers )) }} {{/* Get the best matching cert by name for the vhost. */}} {{ $vhostCert := (closest (dir ) (printf $host))}} {{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} {{ $vhostCert := trimSuffix $vhostCert }} {{ $vhostCert := trimSuffix $vhostCert }} {{/* Use the cert specified on the container or fallback to the best vhost match */}} {{ $cert := (coalesce $certName $vhostCert) }} {{ $is_https := (and (ne $https_method ) (ne $cert ) (or (and (exists (printf $cert)) (exists (printf $cert))) (and (exists (printf $cert)) (exists (printf $cert)))) ) }} {{ if $is_https }} {{ if eq $https_method }} server { server_name {{ $host }}; listen 80 {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:80 {{ $default_server }}; {{ end }} access_log /var/log/nginx/access.log vhost; return 301 https://$host$request_uri; } {{ end }} server { server_name {{ $host }}; listen 443 ssl http2 {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:443 ssl http2 {{ $default_server }}; {{ end }} access_log /var/log/nginx/access.log vhost; {{ if eq $network_tag }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; {{ end }} {{ if eq $ssl_policy }} ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; {{ else if eq $ssl_policy }} ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA'; {{ else if eq $ssl_policy }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA'; {{ end }} ssl_prefer_server_ciphers on; ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; {{ if (and (exists (printf $cert)) (exists (printf $cert))) }} ssl_certificate /etc/nginx/certs/letsencrypt/live/{{ (printf $cert) }}; ssl_certificate_key /etc/nginx/certs/letsencrypt/live/{{ (printf $cert) }}; {{ else if (and (exists (printf $cert)) (exists (printf $cert))) }} ssl_certificate /etc/nginx/certs/{{ (printf $cert) }}; ssl_certificate_key /etc/nginx/certs/{{ (printf $cert) }}; {{ end }} {{ if (exists (printf $cert)) }} ssl_dhparam {{ printf $cert }}; {{ end }} {{ if (exists (printf $cert)) }} ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate {{ printf $cert }}; {{ end }} {{ if (and (ne $https_method ) (ne $hsts )) }} add_header Strict-Transport-Security always; {{ end }} {{ if (exists (printf $host)) }} include {{ printf $host }}; {{ else if (exists ) }} include /etc/nginx/vhost.d/default; {{ end }} location / { {{ if eq $proto }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ else if eq $proto }} root {{ trim $vhost_root }}; include fastcgi.conf; fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} {{ if (exists (printf $host)) }} auth_basic ; auth_basic_user_file {{ (printf $host) }}; {{ end }} {{ if (exists (printf $host)) }} include {{ printf $host}}; {{ else if (exists ) }} include /etc/nginx/vhost.d/default_location; {{ end }} } } {{ end }} {{ if or (not $is_https) (eq $https_method ) }} server { server_name {{ $host }}; listen 80 {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:80 {{ $default_server }}; {{ end }} access_log /var/log/nginx/access.log vhost; {{ if eq $network_tag }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; {{ end }} {{ if (exists (printf $host)) }} include {{ printf $host }}; {{ else if (exists ) }} include /etc/nginx/vhost.d/default; {{ end }} location / { {{ if eq $proto }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ else if eq $proto }} root {{ trim $vhost_root }}; include fastcgi.conf; fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} {{ if (exists (printf $host)) }} auth_basic ; auth_basic_user_file {{ (printf $host) }}; {{ end }} {{ if (exists (printf $host)) }} include {{ printf $host}}; {{ else if (exists ) }} include /etc/nginx/vhost.d/default_location; {{ end }} } } {{ if (and (not $is_https) (exists ) (exists )) }} server { server_name {{ $host }}; listen 443 ssl http2 {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:443 ssl http2 {{ $default_server }}; {{ end }} access_log /var/log/nginx/access.log vhost; return 500; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; } {{ end }} {{ end }} {{ end }}
, nginx /etc/nginx/certs/%s.crt
/etc/nginx/certs/%s.pem
, %s — ( — , ).
/etc/nginx/certs/letsencrypt/live/%s/{fullchain.pem, privkey.pem}
, :
{{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (or (and (exists (printf "/etc/nginx/certs/letsencrypt/live/%s/fullchain.pem" $cert)) (exists (printf "/etc/nginx/certs/letsencrypt/live/%s/privkey.pem" $cert)) ) (and (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) ) ) ) }}
, domains.conf
.
/tank0/docker/services/nginx-proxy/certs/letsencrypt/domains.conf *.NAS.cloudns.cc NAS.cloudns.cc
. , , , client_max_body_size
20, .
/tank0/docker/services/nginx-proxy/local-config/max_upload_size.conf client_max_body_size 20G;
, :
docker-compose up
( ), Ctrl+C :
docker-compose up -d
— nginx, . , , .
, NAS.
.
docker-compose :
/tank0/docker/services/test_nginx/docker-compose.yml version: '2' networks: docker0: external: name: docker0 services: nginx-local: restart: always image: nginx:alpine expose: - 80 - 443 environment: - "VIRTUAL_HOST=test.NAS.cloudns.cc" - "VIRTUAL_PROTO=http" - "VIRTUAL_PORT=80" - CERT_NAME=NAS.cloudns.cc networks: - docker0
:
docker0
— . .expose
— , . , 80 HTTP 443 HTTPS.VIRTUAL_HOST=test.NAS.cloudns.cc
— , nginx-reverse-proxy .VIRTUAL_PROTO=http
— nginx-reverse-proxy . , HTTP.VIRTUAL_PORT=80
— nginx-reverse-proxy.CERT_NAME=NAS.cloudns.cc
— . , , . NAS — DNS .networks
— , nginx-reverse-proxy docker0
.
, . docker-compose up
, test.NAS.cloudns.cc
.
:
$ docker-compose up Creating testnginx_nginx-local_1 Attaching to testnginx_nginx-local_1 nginx-local_1 | 172.22.0.5 - - [29/Jul/2018:15:32:02 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537 (KHTML, like Gecko) Chrome/67.0 Safari/537" "192.168.2.3" nginx-local_1 | 2018/07/29 15:32:02 [error] 8
:

, , , , : .
, Ctrl+C, docker-compose down
.
local-rpoxy
, nginx-default , nas, omv 10080 10443 .
.
/tank0/docker/services/nginx-local/docker-compose.yml version: '2' networks: docker0: external: name: docker0 services: nginx-local: restart: always image: nginx:alpine expose: - 80 - 443 environment: - "VIRTUAL_HOST=NAS.cloudns.cc,nas,nas.*,www.*,omv.*,nas-controller.nas" - "VIRTUAL_PROTO=http" - "VIRTUAL_PORT=80" - CERT_NAME=NAS.cloudns.cc volumes: - ./local-config:/etc/nginx/conf.d networks: - docker0
docker-compose , .
, , , NAS.cloudns.cc
. , NAS DNS , .
/tank0/docker/services/nginx-local/local-config/default.conf # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server map $http_x_forwarded_proto $proxy_x_forwarded_proto { default $http_x_forwarded_proto; '' $scheme; } # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the # server port the client connected to map $http_x_forwarded_port $proxy_x_forwarded_port { default $http_x_forwarded_port; '' $server_port; } # Set appropriate X-Forwarded-Ssl header map $scheme $proxy_x_forwarded_ssl { default off; https on; } access_log on; error_log on; # HTTP 1.1 support proxy_http_version 1.1; proxy_buffering off; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ""; server { server_name _; # This is just an invalid value which will never trigger on a real hostname. listen 80; return 503; } server { server_name www.* nas.* omv.* ""; listen 80; location / { proxy_pass https:
172.21.0.1
— . 443, OMV HTTPS. .https://nas-controller/
— -, IPMI, nas, nas-controller.nas, nas-controller. .
LDAP
LDAP-
LDAP- — .
Docker . , , .
LDIF- .
/tank0/docker/services/ldap/docker-compose.yml version: "2" networks: ldap: docker0: external: name: docker0 services: open-ldap: image: "osixia/openldap:1.2.0" hostname: "open-ldap" restart: always environment: - "LDAP_ORGANISATION=NAS" - "LDAP_DOMAIN=nas.nas" - "LDAP_ADMIN_PASSWORD=ADMIN_PASSWORD" - "LDAP_CONFIG_PASSWORD=CONFIG_PASSWORD" - "LDAP_TLS=true" - "LDAP_TLS_ENFORCE=false" - "LDAP_TLS_CRT_FILENAME=ldap_server.crt" - "LDAP_TLS_KEY_FILENAME=ldap_server.key" - "LDAP_TLS_CA_CRT_FILENAME=ldap_server.crt" volumes: - ./certs:/container/service/slapd/assets/certs - ./ldap_data/var/lib:/var/lib/ldap - ./ldap_data/etc/ldap/slapd.d:/etc/ldap/slapd.d networks: - ldap ports: - 172.21.0.1:389:389 - 172.21.0.1::636:636 phpldapadmin: image: "osixia/phpldapadmin:0.7.1" hostname: "nas.nas" restart: always networks: - ldap - docker0 expose: - 443 links: - open-ldap:open-ldap-server volumes: - ./certs:/container/service/phpldapadmin/assets/apache2/certs environment: - VIRTUAL_HOST=ldap.* - VIRTUAL_PORT=443 - VIRTUAL_PROTO=https - CERT_NAME=NAS.cloudns.cc - "PHPLDAPADMIN_LDAP_HOSTS=open-ldap-server" #- "PHPLDAPADMIN_HTTPS=false" - "PHPLDAPADMIN_HTTPS_CRT_FILENAME=certs/ldap_server.crt" - "PHPLDAPADMIN_HTTPS_KEY_FILENAME=private/ldap_server.key" - "PHPLDAPADMIN_HTTPS_CA_CRT_FILENAME=certs/ldap_server.crt" - "PHPLDAPADMIN_LDAP_CLIENT_TLS_REQCERT=allow" ldap-ssp: image: openfrontier/ldap-ssp:https volumes: #- ./ssp/mods-enabled/ssl.conf:/etc/apache2/mods-enabled/ssl.conf - /etc/ssl/certs/ssl-cert-snakeoil.pem:/etc/ssl/certs/ssl-cert-snakeoil.pem - /etc/ssl/private/ssl-cert-snakeoil.key:/etc/ssl/private/ssl-cert-snakeoil.key restart: always networks: - ldap - docker0 expose: - 80 links: - open-ldap:open-ldap-server environment: - VIRTUAL_HOST=ssp.* - VIRTUAL_PORT=80 - VIRTUAL_PROTO=http - CERT_NAME=NAS.cloudns.cc - "LDAP_URL=ldap://open-ldap-server:389" - "LDAP_BINDDN=cn=admin,dc=nas,dc=nas" - "LDAP_BINDPW=ADMIN_PASSWORD" - "LDAP_BASE=ou=users,dc=nas,dc=nas" - "MAIL_FROM=admin@nas.nas" - "PWD_MIN_LENGTH=8" - "PWD_MIN_LOWER=3" - "PWD_MIN_DIGIT=2" - "SMTP_HOST=" - "SMTP_USER=" - "SMTP_PASS="
:
LDAP- , :
LDAP_ORGANISATION=NAS
— . .LDAP_DOMAIN=nas.nas
— . . , .LDAP_ADMIN_PASSWORD=ADMIN_PASSWORD
— .LDAP_CONFIG_PASSWORD=CONFIG_PASSWORD
— .
-, " ", .
:
/container/service/slapd/assets/certs
certs
— . ../ldap_data/
— , . LDAP .
ldap
, 389 ( LDAP) 636 (LDAP SSL, ) .
PhpLdapAdmin : LDAP ldap
443 docker0
, , nginx-reverse-proxy.
:
VIRTUAL_HOST=ldap.*
— , nginx-reverse-proxy .VIRTUAL_PORT=443
— nginx-reverse-proxy.VIRTUAL_PROTO=https
— nginx-reverse-proxy.CERT_NAME=NAS.cloudns.cc
— , .
SSL .
SSP HTTP .
, , .
— LDAP.
LDAP_URL=ldap://open-ldap-server:389
— LDAP (. links
).LDAP_BINDDN=cn=admin,dc=nas,dc=nas
— .LDAP_BINDPW=ADMIN_PASSWORD
— , , open-ldap.LDAP_BASE=ou=users,dc=nas,dc=nas
— , .
LDAP LDAP :
apt-get install ldap-utils ldapadd -x -H ldap://172.21.0.1 -D "cn=admin,dc=nas,dc=nas" -W -f ldifs/inititialize_ldap.ldif ldapadd -x -H ldap://172.21.0.1 -D "cn=admin,dc=nas,dc=nas" -W -f ldifs/base.ldif ldapadd -x -H ldap://172.21.0.1 -D "cn=admin,cn=config" -W -f ldifs/gitlab_attr.ldif
gitlab_attr.ldif
, Gitlab ( ) .
.
LDAP $ ldapsearch -x -H ldap://172.21.0.1 -b dc=nas,dc=nas -D "cn=admin,dc=nas,dc=nas" -W Enter LDAP Password:
LDAP . WEB-.
OMV LDAP
LDAP , OMV : , , , , — .
LDAP .
:

, , NAS USB.
.
NUT GUI OMV.
"->" , , , , "eaton".
" " :
driver = usbhid-ups port = auto desc = "Eaton 9130 700 VA" vendorid = 0463 pollinterval = 10
driver = usbhid-ups
— USB, USB HID.vendorid
— , lsusb
.pollinterval
— c.
.
lsusb
, :
" " " ".
, :

. , .
.
Conclusion
. , , , , .
— .
-, OMV .
WEB-, , :

Docker WEB-:

, OMV .
:

:

CPU:

.
!
