Implementação de uma plataforma de software NAS segura


Em um artigo anterior , o design da plataforma de software NAS foi descrito.
É hora de implementá-lo.


Verifique


Certifique-se de verificar a saúde da piscina antes de começar:


zpool status -v 

O pool e todos os discos nele devem estar ONLINE.


Além disso, presumo que, no estágio anterior, tudo foi feito de acordo com as instruções e funciona, ou você entende bem o que está fazendo.


Amenidades


Antes de tudo, vale a pena cuidar do gerenciamento conveniente se você não fez isso desde o início.
Será necessário:


  • Servidor SSH: apt-get install openssh-server . Se você não sabe como configurar o SSH, fazendo NAS no Linux é muito cedo Você pode ler os recursos de seu uso neste artigo e , em seguida, usar um dos manuais .
  • tmux ou tela : apt-get install tmux . Para salvar a sessão ao efetuar login via SSH e usar várias janelas.

Depois de instalar o SSH, você precisa adicionar um usuário para não efetuar login via SSH como root (a entrada está desativada por padrão e você não precisa habilitá-la):


 zfs create rpool/home/user adduser user cp -a /etc/skel/.[!.]* /home/user chown -R user:user /home/user 

Para administração remota, isso é um mínimo suficiente.


No entanto, enquanto você precisa manter o teclado e o monitor conectados, como você também precisará reiniciar ao atualizar o kernel e garantir que tudo funcione imediatamente após o carregamento.


Uma alternativa é usar o Virtual KVM, que fornece IME . Existe um console lá, embora no meu caso seja implementado como um applet Java, o que não é muito conveniente.


Personalização


Preparação de cache


Tanto quanto você se lembra, na configuração descrita por mim existe um SSD separado no L2ARC, que ainda não é usado, mas usado "para crescimento".


Opcional, mas é aconselhável preencher esse SSD com dados aleatórios (no caso do Samsung EVO, ele será preenchido com zeros após o blkdiscard, mas não em todos os SSDs):


 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 

Desabilitando a compactação de log


No ZFS, a compactação já é usada, porque a compactação de log por meio do gzip será claramente supérflua.
Desative:


 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 

Atualização do sistema


Tudo é simples aqui:


 apt-get dist-upgrade --yes reboot 

Criando uma captura instantânea para um novo estado


Após a reinicialização, para corrigir o novo estado de funcionamento, você precisa reescrever o primeiro instantâneo:


 zfs destroy rpool/ROOT/debian@install zfs snapshot rpool/ROOT/debian@install 

Organização do sistema de arquivos


Particionando para SLOG


A primeira coisa a fazer para alcançar o desempenho normal do ZFS é colocar o SLOG no SSD.
Deixe-me lembrá-lo de que o SLOG na configuração usada é duplicado em dois SSDs: para isso, os dispositivos no LUKS-XTS serão criados na parte superior da quarta seção de cada 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 

Particionamento para L2ARC e Swap


Primeiro você precisa criar partições sob swap e 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 

A partição de troca e o L2ARC serão criptografados em uma chave aleatória, como após uma reinicialização, eles não são necessários e sempre é possível recriá-los.
Portanto, no crypttab, uma linha é escrita para criptografar / descriptografar partições no modo simples:


 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 

Então você precisa reiniciar os daemons e ativar a troca:


 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 

Porque swapiness não é usado ativamente no SSD; o parâmetro swapiness , que é 60 por padrão, deve ser definido como 10.


O L2ARC ainda não está sendo usado nesta fase, mas a seção já está pronta:


 $ ls /dev/mapper/ control l2arc_crypt root_crypt1 root_crypt2 slog0_crypt1 slog0_crypt2 swap_crypt tank0_crypt0 tank0_crypt1 tank0_crypt2 tank0_crypt3 

Piscinas tanqueN


A criação do pool tank0 será descrita, tank1 é criado por analogia.


Para não criar as mesmas partições manualmente e evitar erros, escrevi um script para criar partições criptografadas para pools:


create_crypt_pool.sh
 #!/bin/bash KEY_SIZE=512 POOL_NAME="$1" KEY_FILE="/etc/keys/${POOL_NAME}.key" LUKS_PARAMS="--verbose --cipher aes-xts-plain64:sha${KEY_SIZE} --key-size $KEY_SIZE" [ -z "$1" ] && { echo "Error: pool name empty!" ; exit 1; } shift [ -z "$*" ] && { echo "Error: devices list empty!" ; exit 1; } echo "Devices: $*" read -p "Is it ok? " a [ "$a" != "y" ] && { echo "Bye"; exit 1; } dd if=/dev/urandom of=$KEY_FILE bs=1 count=4096 phrase="?" read -s -p "Password: " phrase echo read -s -p "Repeat password: " phrase1 echo [ "$phrase" != "$phrase1" ] && { echo "Error: passwords is not equal!" ; exit 1; } echo "### $POOL_NAME" >> /etc/crypttab index=0 for i in $*; do echo "$phrase"|cryptsetup $LUKS_PARAMS luksFormat "$i" || exit 1 echo "$phrase"|cryptsetup luksAddKey "$i" $KEY_FILE || exit 1 dev_name="${POOL_NAME}_crypt${index}" echo "${dev_name} $i $KEY_FILE luks" >> /etc/crypttab cryptsetup luksOpen --key-file $KEY_FILE "$i" "$dev_name" || exit 1 index=$((index + 1)) done echo "###" >> /etc/crypttab phrase="=====================================================" phrase1="=================================================" unset phrase unset phrase1 

Agora, usando este script, você precisa criar um pool para armazenar dados:


 ./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* 

Para notas sobre o parâmetro ashift=12 , consulte meus artigos anteriores e comentários sobre eles.


Depois de criar o pool, coloquei seu log no SSD:


 zpool add tank0 log mirror /dev/disk/by-id/dm-name-slog0_crypt1 /dev/disk/by-id/dm-name-slog0_crypt2 

No futuro, com o OMV instalado e configurado, será possível criar pools por meio da GUI:


A criação do ZFS caiu na OMV WEB GUI


Ativando volumes de importação e montagem automática na inicialização


Para garantir a habilitação de conjuntos de montagem automática, execute os seguintes comandos:


 rm /etc/zfs/zpool.cache systemctl enable zfs-import-scan.service systemctl enable zfs-mount.service systemctl enable zfs-import-cache.service 

Nesta fase, a configuração do subsistema de disco está concluída.


Sistema operacional


O primeiro passo é instalar e configurar o OMV para finalmente obter algum tipo de base para o NAS.


Instalar OMV


O OMV será instalado como um pacote deb. Para fazer isso, é possível usar as instruções oficiais .


O script add_repo.sh inclui o repositório do OMV Arrakis em /etc/apt/ sources.list.d para que o sistema em lote veja o repositório.


add_repo.sh
 cat <<EOF >> /etc/apt/sources.list.d/openmediavault.list deb http://packages.openmediavault.org/public arrakis main # deb http://downloads.sourceforge.net/project/openmediavault/packages arrakis main ## Uncomment the following line to add software from the proposed repository. # deb http://packages.openmediavault.org/public arrakis-proposed main # deb http://downloads.sourceforge.net/project/openmediavault/packages arrakis-proposed main ## This software is not part of OpenMediaVault, but is offered by third-party ## developers as a service to OpenMediaVault users. deb http://packages.openmediavault.org/public arrakis partner # deb http://downloads.sourceforge.net/project/openmediavault/packages arrakis partner EOF 

Observe que, comparado ao original, o repositório do parceiro está incluído.


Para instalar e inicializar, você deve executar os comandos abaixo.


Comandos para instalar o 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 # Initialize the system and database. omv-initsystem 

OMV instalado. Ele usa seu próprio kernel e, após a instalação, uma reinicialização pode ser necessária.


Após a reinicialização, a interface do OpenMediaVault estará disponível na porta 80 (vá para o navegador no NAS por endereço IP):



O nome de usuário / senha padrão é admin/openmediavault .


Configurar OMV


Além disso, a maior parte da configuração passa pela WEB-GUI.


Estabelecer uma conexão segura


Agora você precisa alterar a senha do administrador da WEB e gerar um certificado para o NAS para trabalhar no HTTPS no futuro.


A senha é alterada na guia "Sistema-> Configurações gerais-> Senha do administrador da web" .
Para gerar um certificado na guia "Sistema-> Certificados-> SSL", selecione "Adicionar-> Criar" .


O certificado criado ficará visível na mesma guia:


Certificado


Após criar o certificado, na guia "Sistema-> Configurações gerais", ative a caixa de seleção "Ativar SSL / TLS" .


Um certificado será necessário antes da conclusão da configuração. A versão final usará um certificado assinado para entrar em contato com a OMV.


Agora você precisa efetuar login no OMV, na porta 443 ou simplesmente atribuir o prefixo https:// ao IP no navegador.


Se você conseguiu fazer login, na guia "Sistema-> Configurações gerais", você precisa habilitar a caixa de seleção "Forçar SSL / TLS".


Altere as portas 80 e 443 para 10080 e 10443 .
E tente fazer login no seguinte endereço: https://IP_NAS:10443 .
A alteração de portas é importante porque as portas 80 e 443 usarão o contêiner do docker com o proxy nginx-reverse.


Configurações primárias


As configurações mínimas que devem ser feitas primeiro:


  • Na guia "Sistema-> Data e Hora", verifique o valor do fuso horário e defina o servidor NTP.
  • Na guia "Sistema-> Monitoramento", habilite a coleta de estatísticas de desempenho.
  • Na guia "Sistema-> Gerenciamento de energia", provavelmente vale a pena desligar o "Monitoramento" para que o OMV não tente controlar os ventiladores.

Rede


Se a segunda interface de rede NAS ainda não estiver conectada, conecte-a ao roteador.


Então:


  • Na guia "Sistema-> Rede", defina o nome do host como "nas" (ou o que você quiser).
  • Configure a ligação para as interfaces, conforme mostrado na figura abaixo: "Sistema-> Rede-> Interfaces-> Adicionar-> Bond" .
  • Adicione as regras de firewall necessárias na guia "Sistema-> Rede-> Firewall" . Primeiro, o acesso às portas 10443, 10080, 443, 80, 22 para SSH e a permissão para receber / enviar ICMP são suficientes.

Configuração de ligação


Como resultado, as interfaces na ligação devem aparecer, que o roteador verá como uma interface e atribuir a ele um endereço IP:


Interfaces de ligação


Se desejado, é possível configurar adicionalmente o SSH a partir da GUI WEB:


Configuração SSH


Repositórios e módulos


Na guia "Sistema-> Gerenciamento de atualizações-> Configurações", ative "Atualizações suportadas pela comunidade" .


Primeiro, adicione repositórios extras OMV .
Isso pode ser feito simplesmente instalando o plug-in ou pacote, conforme indicado no fórum .


Na página "Sistema-> Plugins", você precisa encontrar o plugin "openmediavault-omvextrasorg" e instalá-lo.


Como resultado, o ícone "OMV-Extras" aparecerá no menu do sistema (pode ser visto nas capturas de tela).


Vá para lá e ative os seguintes repositórios:


  • OMV-Extras.org. Um repositório estável contendo muitos plugins.
  • Teste OMV-Extras.org. Alguns plugins deste repositório não estão no repositório estável.
  • Docker CE. Na verdade, Docker.

Na aba "Sistema-> OMV Extras-> Kernel", você pode selecionar o kernel que precisa, incluindo o kernel do Proxmox (eu não instalei por conta própria, porque ainda não preciso, por isso não o recomendo):



Instale os plugins necessários ( negrito absolutamente necessário, em itálico - opcional, que eu não instalei):


Lista de plugins.
  • openmediavault-apttool. GUI mínima para trabalhar com um sistema em lote. Adiciona "Serviços-> Apttool" .
  • openmediavault-anacron. Adiciona a capacidade de trabalhar a partir da GUI com um planejador assíncrono. Adiciona "Sistema-> Anacron" .
  • openmediavault-backup. Fornece sistema de backup em armazenamento. Adiciona uma página "Sistema -> Backup" .
  • openmediavault-diskstats. Necessário para coletar estatísticas sobre o desempenho do disco.
  • openmediavault-dnsmasq . Permite aumentar o servidor DNS e o DHCP no NAS. Como faço isso em um roteador, não preciso disso.
  • openmediavault-docker-gui . Interface de gerenciamento de contêiner do Docker. Adiciona "Serviços-> Docker" .
  • openmediavault-ldap . Suporte para autenticação através do LDAP. Adiciona "Gerenciamento de Direitos -> Serviço de Diretório" .
  • openmediavault-letsencrypt . Suporte para Let's Encrypt da GUI. Não é necessário, porque usa incorporação no contêiner nginx-reverse-proxy.
  • openmediavault-luksencryption . Suporte de criptografia LUKS. É necessário que os discos criptografados estejam visíveis na interface OMV. Adiciona "Armazenamento-> Criptografia" .
  • openmediavault-nuts . Suporte UPS. Adiciona "Serviços-> UPS" .
  • openmediavault-omvextrasorg . OMV Extras já deve estar instalado.
  • openmediavault-resetperms. Permite redefinir permissões e redefinir listas de controle de acesso em diretórios compartilhados. Adiciona "Controle de acesso -> Diretórios gerais -> Redefinir permissões" .
  • openmediavault-route. Plug-in útil para gerenciamento de roteamento. Adiciona "Sistema-> Rede-> Rota estática" .
  • openmediavault-symlinks. Fornece a capacidade de criar links simbólicos. Adiciona a página "Serviços-> Links simbólicos" .
  • openmediavault-unionfilesystems. Suporte do UnionFS. Pode ser útil no futuro, embora a janela de encaixe use o ZFS como back-end. Adiciona "Armazenamento-> Sistemas de Arquivos Union" .
  • openmediavault-virtualbox . Ele pode ser usado para incorporar recursos de gerenciamento de máquinas virtuais na GUI.
  • openmediavault-zfs . O plug-in adiciona suporte ao ZFS no OpenMediaVault. Após a instalação, a página "Armazenamento-> ZFS" será exibida.

Discos


Todos os discos que estão no sistema devem ser OMV visíveis. Certifique-se disso consultando a guia "Armazenamento-> Discos" . Se nem todos os discos estiverem visíveis, execute uma digitalização.


Discos no sistema


Lá, em todos os HDDs, o cache de gravação deve estar ativado (clicando em um disco da lista e clicando no botão "Editar").


Verifique se todas as seções criptografadas estão visíveis na guia "Armazenamento-> Criptografia" :


Partições Criptografadas


Agora é hora de configurar o SMART, indicado como um meio de aumentar a confiabilidade:


  • Vá para a guia "Armazenamento-> SMART-> Configurações" . Ligue o SMART.
  • No mesmo local, selecione os valores dos níveis de temperatura dos discos (crítico, geralmente 60 C, e o regime ideal de temperatura do disco 15-45 C).
  • Vá para a guia "Armazenamento-> SMART-> Dispositivos" . Ative o monitoramento para cada unidade.
  • Vá para a guia "Armazenamento-> SMART-> Testes agendados" . Adicione um autoteste curto uma vez ao dia para cada disco e um autoteste longo uma vez ao mês. Além disso, para que os períodos de autoteste não se sobreponham.

Nisso, a configuração do disco pode ser considerada completa.


Sistemas de arquivos e diretórios compartilhados


Você deve criar sistemas de arquivos para diretórios predefinidos.
Isso pode ser feito no console ou na interface OMV WEB ( Armazenamento-> ZFS-> Selecionar pool tank0-> Botão Adicionar -> Sistema de arquivos ).


Comandos para criar o 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 

O resultado deve ser a seguinte estrutura de diretórios:



Depois disso, adicione os FSs criados como diretórios compartilhados na página "Gerenciando Direitos de Acesso- > Diretórios Gerais- > Adicionar" .
Observe que o parâmetro "Device" é igual ao caminho para o sistema de arquivos criado no ZFS, e o parâmetro "Path" para todos os diretórios é "/".



Backup


O backup é feito por duas ferramentas:



Se você usar o plug-in, provavelmente receberá um erro:


 lsblk: /dev/block/0:22: not a block device 

Para corrigi-lo, conforme observado pelos desenvolvedores do OMV nesta "configuração muito fora do padrão", seria possível recusar o plug-in e usar as ferramentas do ZFS na forma de zfs send/receive .
Ou especifique explicitamente o parâmetro "Dispositivo raiz" na forma de um dispositivo físico do qual o download é feito.
É mais conveniente usar o plug-in e fazer backup do sistema operacional a partir da interface, em vez de enquadrar algo com o zfs send, por isso prefiro a segunda opção.


Configuração de backup


Para fazer o backup funcionar, primeiro crie o sistema de arquivos tank0/apps/backup por meio do ZFS, depois no menu "Sistema-> Backup", clique em "+" no campo de parâmetro "Pasta pública" e adicione o dispositivo criado como destino e o campo "Caminho" defina como "/".


Também há problemas com o zfs-auto-snapshot. Se não estiver configurada, ela tirará fotos a cada hora, todos os dias, todas as semanas, todos os meses durante um ano.
O resultado é o que está na captura de tela:


Muito spam do zfs-auto-snapshot


Se você já se deparou com isso, execute o seguinte código para remover instantâneos automáticos:


 zfs list -t snapshot -o name -S creation | grep "@zfs-auto-snap" | tail -n +1500 | xargs -n 1 zfs destroy -vr 

Em seguida, configure o zfs-auto-snapshot para executar no cron.
Para começar, exclua /etc/cron.hourly/zfs-auto-snapshot se você não precisar tirar fotos a cada hora.


Notificações por email


A notificação por email foi indicada como um dos meios para obter confiabilidade.
Portanto, agora você precisa configurar as notificações por email.
Para fazer isso, registre uma caixa em um dos servidores públicos (bem, ou configure você mesmo o servidor SMTP, se você realmente tiver motivos para isso).


Então você precisa ir para a página "Sistema-> Notificação" e digitar:


  • Endereço do servidor SMTP.
  • Porta do servidor SMTP.
  • Nome de usuário
  • Endereço do remetente (geralmente o primeiro componente do endereço corresponde ao nome).
  • Senha do usuário
  • No campo "Destinatário", seu endereço usual para o qual o NAS enviará notificações.

É altamente recomendável ativar o SSL / TLS.


Um exemplo de configuração para o Yandex é mostrado na captura de tela:


Notificações por email


Configuração de rede fora do NAS


Endereço IP


Eu uso um endereço IP estático branco, que custa mais 100 rublos por mês. Se não houver desejo de pagamento e seu endereço for dinâmico, mas não para NAT, é possível ajustar registros DNS externos por meio da API do serviço selecionado.
No entanto, deve-se ter em mente que um endereço não NAT pode repentinamente se tornar um endereço NAT: como regra, os provedores não dão nenhuma garantia.


Roteador


Como roteador, tenho um Mikrotik RouterBoard , semelhante ao da figura abaixo.


Mikrotik routerboard


Três coisas são necessárias no roteador:


  • Configure endereços estáticos para o NAS. No meu caso, os endereços são emitidos via DHCP e eu preciso garantir que os adaptadores com um endereço MAC específico sempre obtenham o mesmo endereço IP. No RouterOS, isso é feito na guia "IP-> Servidor DHCP", com o botão "Tornar estático" .
  • Configure o servidor DNS para que, para o nome "nas", bem como nomes que terminem em ".nas" e ".NAS.cloudns.cc" (onde "NAS" seja a zona do ClouDNS ou um serviço similar), forneça ao sistema IP. Onde fazer isso no RouterOS é mostrado na captura de tela abaixo. No meu caso, isso é implementado combinando o nome com uma expressão regular: " ^.*\.nas$|^nas$|^.*\.NAS.cloudns.cc$ "
  • Configure o encaminhamento de porta. No RouterOS, isso é feito na guia "IP-> Firewall" , não vou me aprofundar nisso.

Configurar o DNS no RouterOS


ClouDNS


CLouDNS é simples. Crie uma conta, confirme. Os registros NS já serão registrados com você. Em seguida, é necessária uma configuração mínima.


Primeiro, você precisa criar as zonas necessárias (a zona com o nome NAS destacado em vermelho na captura de tela é o que você deve criar com um nome diferente, é claro).


Criando uma zona no ClouDNS


Em segundo lugar, nessa zona, você deve registrar os seguintes registros A :


  • nas , www , omv , control e um nome vazio . Para acessar a interface OMV.
  • LDAP . Interface PhpLdapAdmin
  • ssp . Interface para alterar senhas de usuário.
  • teste . Servidor de teste.

Os nomes de domínio restantes serão adicionados à medida que os serviços forem adicionados.
Clique na zona e, em seguida, em "Adicionar novo registro" , selecione o tipo A, digite o nome da zona e o endereço IP do roteador atrás do qual o NAS está.


Added A Records


Em segundo lugar, você precisa acessar a API. No ClouDNS, ele é pago, então você deve primeiro pagar por ele. Em outros serviços, é gratuito. Se você sabe o que é melhor, e isso é suportado pelo Lexicon , escreva nos comentários.


Tendo obtido acesso à API, você precisa adicionar um novo usuário à API.


Adicionando usuário da API ClouDNS


"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 $ "ID" .Docker.CurrentContainerID | first }} {{ define "upstream" }} {{ 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 "upgrade"; 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 "/etc/nginx/dhparam/dhparam.pem") }} 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 "/etc/nginx/proxy.conf") }} 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) "") "true" }} 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 "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 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 $ "Env.VIRTUAL_HOST" "," }} {{ $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 "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} ## Can be connected with "{{ $containerNetwork.Name }}" network {{/* If only 1 port exposed, use that */}} {{ if eq $addrLen 1 }} {{ $address := index $container.Addresses 0 }} {{ template "upstream" (dict "Container" $container "Address" $address "Network" $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 "80" }} {{ $address := where $container.Addresses "Port" $port | first }} {{ template "upstream" (dict "Container" $container "Address" $address "Network" $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 "default_server") $host }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} {{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to "Mozilla-Intermediate" */}} {{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "Mozilla-Intermediate" }} {{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} {{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }} {{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} {{/* Get the first cert name defined by containers w/ the same vhost */}} {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} {{/* Get the best matching cert by name for the vhost. */}} {{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} {{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} {{ $vhostCert := trimSuffix ".crt" $vhostCert }} {{ $vhostCert := trimSuffix ".key" $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 "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)))) ) }} {{ if $is_https }} {{ if eq $https_method "redirect" }} 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 "internal" }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; {{ end }} {{ if eq $ssl_policy "Mozilla-Modern" }} 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 "Mozilla-Intermediate" }} 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 "Mozilla-Old" }} 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 "AWS-TLS-1-2-2017-01" }} 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 "AWS-TLS-1-1-2017-01" }} 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 "AWS-2016-08" }} 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 "AWS-2015-05" }} 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 "AWS-2015-03" }} 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 "AWS-2015-02" }} 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 "/etc/nginx/certs/letsencrypt/live/%s/fullchain.pem" $cert)) (exists (printf "/etc/nginx/certs/letsencrypt/live/%s/privkey.pem" $cert))) }} ssl_certificate /etc/nginx/certs/letsencrypt/live/{{ (printf "%s/fullchain.pem" $cert) }}; ssl_certificate_key /etc/nginx/certs/letsencrypt/live/{{ (printf "%s/privkey.pem" $cert) }}; {{ else if (and (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; {{ end }} {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; {{ end }} {{ if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; {{ end }} {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }} add_header Strict-Transport-Security "{{ trim $hsts }}" always; {{ end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s" $host }}; {{ else if (exists "/etc/nginx/vhost.d/default") }} include /etc/nginx/vhost.d/default; {{ end }} location / { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ else if eq $proto "fastcgi" }} root {{ trim $vhost_root }}; include fastcgi.conf; fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} auth_basic "Restricted {{ $host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; {{ end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; {{ else if (exists "/etc/nginx/vhost.d/default_location") }} include /etc/nginx/vhost.d/default_location; {{ end }} } } {{ end }} {{ if or (not $is_https) (eq $https_method "noredirect") }} 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 "internal" }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; {{ end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s" $host }}; {{ else if (exists "/etc/nginx/vhost.d/default") }} include /etc/nginx/vhost.d/default; {{ end }} location / { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ else if eq $proto "fastcgi" }} root {{ trim $vhost_root }}; include fastcgi.conf; fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} auth_basic "Restricted {{ $host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; {{ end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; {{ else if (exists "/etc/nginx/vhost.d/default_location") }} include /etc/nginx/vhost.d/default_location; {{ end }} } } {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} 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#8: *2 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.22.0.5, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "test.NAS.cloudns.cc", referrer: "https://test.NAS.cloudns.cc/" nginx-local_1 | 172.22.0.5 - - [29/Jul/2018:15:32:02 +0000] "GET /favicon.ico HTTP/1.1" 404 572 "https://test.NAS.cloudns.cc/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537 (KHTML, like Gecko) Chrome/67.0 Safari/537" "192.168.2.3" 

:


Lançado Nginx


, , , , : .


, 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:10443/; } } # nas-controller server { server_name nas-controller.nas; listen 80 ; location / { proxy_pass https://nas-controller/; } } 

  • 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: # extended LDIF # # LDAPv3 # base <dc=nas,dc=nas> with scope subtree # filter: (objectclass=*) # requesting: ALL # # nas.nas dn: dc=nas,dc=nas objectClass: top objectClass: dcObject objectClass: organization o: NAS dc: nas # admin, nas.nas dn: cn=admin,dc=nas,dc=nas objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator ... # ldap_users, groups, nas.nas dn: cn=ldap_users,ou=groups,dc=nas,dc=nas cn: ldap_users gidNumber: 500 objectClass: posixGroup objectClass: top # search result search: 2 result: 0 Success # numResponses: 12 # numEntries: 11 

LDAP . WEB-.


OMV LDAP


LDAP , OMV : , , , , — .


LDAP .


:


Configurar OMV para trabalhar com 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 , :


 # lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub --> Bus 001 Device 003: ID 0463:ffff MGE UPS Systems UPS Bus 001 Device 004: ID 046b:ff10 American Megatrends, Inc. Virtual Keyboard and Mouse Bus 001 Device 002: ID 046b:ff01 American Megatrends, Inc. Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub 

" " " ".
, :


Configuração do no-break


. , .
.



. , , , , .
— .


-, OMV .


WEB-, , :



Docker WEB-:



, OMV .


:


Programação de uso da rede


:


Gráfico de uso de memória


CPU:


Gráfico de uso da CPU




.
!


Source: https://habr.com/ru/post/pt415779/


All Articles