
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:
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:

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
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
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:

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.

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

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

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.

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" :

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.

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:

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:

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.

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.

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).

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á.

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.

"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
, :
" " " ".
, :

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

Docker WEB-:

, OMV .
:

:

CPU:

.
!
