Como rodar NodeJS em servidor Windows

 

Atualizado em 13/10/2019 com mais informações sobre PM2!

O método que recomendo atualmente é o último, independente do seu sistema operacional. Inclusive incluí um vídeo sobre ele, então vá direto para o final do artigo.

Agora se realmente precisa rodar em Windows Server à moda antiga, pode continuar lendo…

Dizem que Node.js roda melhor em Linux. Como eu não sou lá muito fã de tela preta e queria colocar um projeto no ar de uma vez, acabei optando por rodar em Windows Server mesmo. No entanto deu um pouco mais de trabalho do que eu previa. De qualquer forma, resolvi organizar a trabalheira aqui para ajudar quem estiver nos mesmos apuros ou para eu mesmo me lembrar no futuro, hehehe.

Saliento que minha aplicação está usando Express, o que pode mudar alguma coisa em relação ao passo-a-passo, dependendo do seu projeto, mas não sei exatamente o quê…

O quê, você não faz a mínima ideia do motivo de eu estar usando Node.js? Dá uma olhada então nesse post aqui que você vai entender.

Se o que você estava buscando era um tutorial de como PROGRAMAR em NodeJS, o link certo é esse aqui.

Os passos para conseguir rodar uma aplicação Node.js no Windows são:

  1. Derrubar o IIS
  2. Desativar Web Deploy
  3. Liberar o Firewall
  4. Configurar a porta 80
  5. Instalar o Node.js
  6. Instalar o Windows Service
  7. Bônus: PM2

Passo 1: Derrubar o IIS

Se você tem o IIS instalado no seu servidor, o primeiro passo é parar ele, para que possamos usar a porta 80 do IIS para nossa aplicação Node.js (afinal, você não vai querer o seu usuário tendo de digitar a porta 3000 ao lado da sua URL, certo?). Existem outras alternativas para rotear o tráfego do IIS para o Node, que dizem inclusive ser mais profissional, mas deixo isso para você estudar por conta.

Você pode pausar o IIS rodando o seguinte comando com permissão de administrador no Executar/Run do Windows (Windows + R).

Ele vai perguntar se você tem certeza, basta confirmar com Y.

Passo 2: Desativar Web Deploy

Se você tem instalado Web Deploy no seu servidor (eu tinha), ele também estará ocupando a porta 80, temos de derrubar ele também. Para isso, abra o Executar/Run novamente e digite:

Isso vai abrir o gerenciador de serviços do Windows. Procure pelo serviço Web Deployment Agent Service e dê um Stop nele. Mais que isso, altere para que ele não inicie automaticamente com o Windows, para evitar problemas futuros.

Passo 3: Liberar o Firewall

O próximo passo é desbloquear a porta 80 no Firewall do Windows. Na caixa Iniciar do Windows digite Firewall e irá aparecer o ícone correto. Abra o gerenciador do Firewall e clique em Inbound Rules, lá, adicione uma nova regra para permitir acesso à porta 80, configurando a mesma na aba Ports and Protocols. Confirme tudo antes de sair.

Passo 4: Configurar a porta 80

Por padrão os apps Node.js rodam na porta 3000 (ao menos usando Express). Se quiser que ele rode na porta 80, além de preparar o servidor como fiz acima, deve alterar o arquivo www dentro da pasta bin do seu projeto Express. Dentro dele (abra com o notepad) verá que a porta 3000 é citada em uma dada linha, apenas altere para 80.

Curso Node.js e MongoDB
Curso Node.js e MongoDB

Passo 5: Intalar o Node.js

Baixe e instale no servidor a versão mais recente disponível para Windows no site oficial do NodeJS.

Depois de instalado, vá novamente no Executar/Run e digite:

Isso deve lhe devolver a versão do NodeJS instalada no servidor. Se não funcionar, reinicie o servidor e tente novamente.

Publique a sua aplicação NodeJS em uma pasta do servidor. Minha sugestão é C:\domains\nomedoapp\www.

Abra uma janela do CMD com permissão de administrador e navegue usando cd até a pasta da sua aplicação Node.js. Exemplo:

Uma vez lá, digite o seguinte comando para instalar as dependências do seu projeto:

Isso deverá ser o suficiente, mas se quiser ter certeza de que tudo que necessita para rodar Node.js está instalado em seu servidor, execute também os seguintes comandos em sequência:

Agora finalmente execute seu app Node.js com o comando abaixo ainda “dentro” da pasta do seu projeto (ou navegue novamente usando cd):

Passo 6: Instalar o Windows Service

Por padrão, o seu site Node.js ficará executando enquanto a janela do console que iniciou seu site estiver funcionando. Se você fechar ela, ou seu servidor reiniciar (malditos Windows Updates!) já era, seu site vai ficar fora do ar até que você execute o npm start de novo.

Para que isso não aconteça, você deve instalar seu site como um Windows Service. Para fazer isso, primeiro instale o módulo node-windows globalmente:

Agora rode o seguinte comando (dentro da pasta do seu projeto) para incluir uma referência deste módulo ao seu projeto:

Depois, dentro do seu projeto Node.js (na raiz mesmo) crie um arquivo service.js com o seguinte conteúdo:

Troque as propriedades name e description de acordo com seu gosto, mas atente à propriedade script nesse código, que deve conter o caminho absoluto até o arquivo JS que inicia sua aplicação. No meu caso, como estou usando express, estou apontando para o arquivo www que fica na pasta bin do projeto (curiosamente ele não possui extensão, mas é um arquivo).

Se você fez tudo corretamente, vá até Ferramentas Administrativas > Serviços (Administrative Tools > Services ou services.msc no Run/Executar do Windows) e seu serviço vai aparecer lá com o name que definiu ali no script, lhe permitindo alterar suas configurações de inicialização, dar Start, Stop, etc.

Outra coisa bacana desse módulo é que ele manda todas as mensagens para o Event Viewer/Visualizador de Eventos do Windows. Assim, caso sua aplicação Node.js não esteja funcionando ou seu serviço não esteja inicializando, basta dar uma olhada lá, na seção Windows > Applications para entender o que está acontecendo.

Caso precise remover esse serviço (para instalar uma versão mais atualizada, por exemplo) rode o comando abaixo no cmd:

Esse servicename você encontra nas propriedades do Windows Service que deseja excluir.

Bônus: PM2

PM2 é um projeto open-source criado e mantido pela empresa Keymetrics.io, que além do PM2 (que é gratuito) vende um serviço de gerenciamento de performance de aplicações Node.js homônimo. Só para você ter uma ideia do que o PM2 é hoje, são mais de 20M de downloads e empresas como IBM, Microsoft e PayPal usando, o que o torna, disparado, a melhor solução de process manager pra Node, muito mais do que seus principais concorrentes, o Forever e o Nodemon.

Abaixo, eu incluí um pequeno tutorial, que também pode ser assistido nesse vídeo do meu canal:

Pra usar o PM2 é muito simples, primeiro instale globalmente o módulo do PM2:

Depois, quando quiser iniciar o processo da sua aplicação Node.js:

A partir de agora este processo estará rodando “eternamente” com o nome de “myApp”. Opcionalmente você pode usar os comandos abaixo:

  • pm2 ls: para listar os processos existentes;
  • pm2 restart myApp: para reiniciar o processo myApp;
  • pm2 stop myApp: para derrubar o processo myApp;
  • pm2 delete myApp: para excluir o processo myApp;
  • pm2 logs –lines 100: para exibir as últimas 100 linhas de logs dos processos;

Caso você utilize dotenv ou dotenv-safe, é importante que antes de inicializar a sua aplicação, que você rode o PM2 a partir da raiz da pasta do projeto em questão (basta usar cd), para que ele encontre os arquivos .env e .env.example (no caso de dotenv-safe).

Note também que, caso sua aplicação dependa de outros processos, como o MongoDB, por exemplo, eles também devem estar rodando como serviços/workers para que o seu sistema como um todo funciona corretamente. O PM2 pode ajudar nestes casos também, ele é bem genérico.

E para saber mais dos comandos possíveis, você pode estudar o guia oficial dele.

De nada! 😉

Curtiu o post? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js!

Administrando MongoDB: User & Password

Este artigo possui versão em videoaula, exclusiva para os alunos do meu curso de Node.js e MongoDB.

Nesta altura do campeonato é bem possível que você saiba que adoro Node.js e MongoDB. Mas caso esteja chegando agora, trabalho com estas tecnologias desde 2015, tenho alguns livros publicados sobre estes assuntos e até um curso online em videoaulas.

No entanto, eu estou mais para o lado “programador” destas duas tecnologias do que para o lado “administrador”, nunca fui um “cara de infra”. Ainda assim, eu sei me virar e sei os fundamentos básicos a ponto de poder lhe ajudar nos primeiros passos de administração de um servidor MongoDB, por exemplo.

Embora a opção mais segura e confiável seja utilizar serviços em nuvem como Atlas e Mlab, eles são muito caros, o que inviabiliza pequenos projetos. Pensando nesse segundo público, no artigo de hoje, o primeiro de uma série sobre administração de MongoDB, vou ensinar como você pode adicionar usuário e senha no seu servidor MongoDB, uma vez que por padrão ele vem “aberto”.

Atenção: existe estudos que mostram que existem mais de 30.000 instâncias de MongoDB expostas sem usuário e senha na Internet. Não faça parte dessa lista de tolos, implemente autenticação no seu banco de dados.

Subindo uma instância nova de MongoDB

Não vou repetir aqui todo o passo a passo de MongoDB para iniciantes em NoSQL. Essa é uma ótima série aqui do blog e recomendo que dê uma lida nela caso esteja começando agora com Mongo. Baixe a versão community (gratuita) do MongoDB no site oficial e coloque uma instância para rodar usando o comando abaixo (dentro do diretório bin da sua instalação de Mongo).

A variável dbpath eu apontei para uma pasta mongoauth/data por uma questão de organização (crie essa pasta se quiser seguir a mesma linha de raciocínio que a minha).

Já a variável port eu coloquei para definir outra porta para o meu MongoDB por uma questão de segurança. Atacantes de bancos de dados sempre usam as portas padrões dos bancos para tentar invadi-los e é um chamariz para bandido deixar o MongoDB na porta 27017, troque para outro à sua escolha (mais dicas como essa, aqui).

Para testar se sua instância está funcionando, em outra janela do terminal rode o comando abaixo para se conectar, sem qualquer credencial ao banco local.

Lembre-se de usar a mesma porta da instância que você subiu anteriormente.

Terminais mongod e mongo
Terminais mongod e mongo

Agora, para testarmos via software, instale o Node.js na sua máquina a partir do site oficial (tanto faz a versão) e rode o comando abaixo para inicializar um projeto na sua pasta mongoauth que foi criada anteriormente.

Apenas siga respondendo às perguntas que ele fizer e depois rode o comando abaixo para instalar a dependência do MongoDB Node.js Driver que vamos usar.

Depois crie um arquivo index.js na raiz dessa pasta para colar o código Javascript abaixo, que apenas testa a conexão com o Mongo e printa no console o resultado.

Esse código não é o foco aqui do artigo, mas ele se conecta na instância local do Mongo, porta 27018 e, se funcionar, imprime as informações da conexão. Se não funcionar, imprime o erro.

Para testar, apenas rode o comando abaixo no terminal, dentro da pasta do projeto (para funcionar, certifique-se de que a janela de terminal do mongod esteja rodando ou derrube-a para simular erro).

Exemplo de sucesso:

Conexão sem usuário OK
Conexão sem usuário OK

Exemplo de erro:

Erro de conexão no Mongo
Erro de conexão no Mongo

Note que o erro é bem claro em informar que foi uma falha de rede, que ele não encontrou um banco Mongo no endereço informado. Mais pra frente vamos simular erros de autenticação. Agora que temos esta estrutura mínima pronta, vamos adicionar usuário e senha neste banco, para não deixá-lo mais aberto.

Adicionando usuário e senha admin

O primeiro passo de autenticação é criarmos um usuário e senha de administrador, certo? Mais tarde podemos criar usuários com menos privilégios para bancos específicos, mas por ora, temos de ter o master.

Certifique-se de que sua instância do mongod continua rodando. Conecte-se à ela usando outra janela de terminal com o utilitário mongo (fizemos isso antes, lembra?). Agora execute os seguintes comandos no terminal mongo:

O primeiro comando aponta para o banco admin do MongoDB, o equivalente à database master de outros SGBDs. Já o segundo, cria um novo usuário com o nome, senha e perfil de acesso especificado. “userAdminAnyDatabase” vai conferir poderes totais à esse usuário, então crie ele com uma senha bem forte, por favor.

Agora, derrube a sua instância de mongodb e suba ela de novo, mas com uma variação no comando:

O –auth fará com que o seu banco esteja “protegido” com usuário e senha a partir de agora. Se você tentar se conectar com o utilitário mongo, sem passar usuário e senha, até vai rolar localmente, mas não vai conseguir fazer nada pois nenhum banco de dados será visível para você (experimente um ‘show databases’ e verá que não retorna nada) e mesmo que tente criar um, consultar, etc não vai rolar.

Agora, tente se conectar via terminal usando o comando abaixo, em que passo usuário e senha:

E depois, com um ‘show databases’ você vai ver que possui privilégios totais nesta instância de Mongo.

Agora, se tentar passar uma senha errada, terá como retorno um “authentication failed”. E o nosso código Node.js? O mesmo vale para as conexões anônimas locais: não vai dar erro, mas também não vai fazer nada nessa instância de Mongo.

Para poder fazer suas consultas, inserções, etc será necessário se autenticar. Mas não vamos nos autenticar como admin em uma aplicação, certo? Vamos criar um user específico para ela.

Adicionando usuário e senha de aplicação

Usuário admin é para o administrador da instância de Mongo, onde podem existir diversos bancos de dados. Considerando que cada aplicação tenha o seu banco, crie um usuário isolado para cada uma. O processo é idêntico ao realizado para criar o user admin, mas agora muda a role e o nome do usuário, como abaixo:

Aqui foi criado um usuário luiz, dentro da database teste com permissão de “dono” nesta database, ou seja, ele pode fazer leituras e escritas livremente em todas coleções da database teste.

Reforço que criei o user na própria database teste, deixando a database admin apenas para administradores. Agora, para se conectar ao banco teste localmente será necessário o comando abaixo:

Note que no último parâmetro coloquei a base de dados onde existe o usuário e senha informados. Já no Node.js, passamos essas informações na própria connection string, respeitando URI encoding (caracteres especiais tem de ser codificados para URI):

A sintaxe é “usuário:[email protected]:porta/?authSource=banco-com-user”. Experimente colocar uma senha errada e você deve receber um erro de authentication failed no seu console do Node.js. E com isso encerramos este artigo de administração de MongoDB. Espero ter ajudado!

Espero que este artigo tenha sido útil para você que está aprendendo Node.js e MongoDB. Para conteúdo mais aprofundado, recomendo meus livros. Para videoaulas, recomendo o meu curso online.

Curso Node.js e MongoDB
Curso Node.js e MongoDB

O guia completo do package.json do Node.js

NPM
NPM

O package.json é um elemento-chave em muitas aplicações do ecossistema Node.js. Se você trabalha com JavaScript, ou se você já interagiu com um projeto JavaScript antes, Node.js ou front-end, você certamente já se deparou com um arquivo package.json.

Para quê ele serve?

O que você deveria saber sobre ele e que coisas legais pode fazer com ele?

O package.json é uma espécie de manifesto do seu projeto. Ele pode fazer várias coisas, completamente não relacionadas. Ele é um repositório central de configurações de ferramentas, por exemplo. Ele também é onde npm armazena os nomes e versões dos pacotes instalados.

Neste artigo você vai ver:

Vamos lá!

A estrutura do arquivo

Aqui temos um exemplo de arquivo package.json válido:

Está vazio Não existem exigências fixas do que deve estar em um arquivo package.json para uma aplicação. O único requisito é que ele respeite o formato JSON, de outra maneira ele não poderá ser lido pelos programas que tentarem acessar suas propriedades programaticamente. Se você está construindo um pacote Node.js que você quer distribuir através do npm, as coisas mudam radicalmente e você deve ter um conjunto de propriedades que ajudem outras pessoas a usá-lo. Veremos mais sobre isso mais tarde. Este é outro package.json válido:

Ele define uma propriedade name, que diz o nome da aplicação ou pacote, que está contido na mesma pasta onde o arquivo vive. Aqui temos um exemplo muito mais complexo, o qual eu extraí de uma aplicação Vue.js de exemplo:

Existem muitas coisas acontecendo aqui:

  • name define o nome da aplicação ou pacote;
  • version indica a versão atual;
  • description é um resumo da sua aplicação/pacote;
  • main define o ponto de entrada da aplicação;
  • private (true) previne a sua aplicação de ser publicada acidentalmente no npm;
  • scripts define um conjunto de scripts Node para você executar;
  • dependencies define uma lista de pacotes npm instalados como dependências;
  • devDependencies define uma lista de pacotes npm instalados como dependências de desenvolvimento;
  • engines define quais versões de Node este pacote/aplicação funciona;
  • browserslist é usado para dizer quais browsers (e versões) você quer suportar;

Todas estas propriedades são usadas tanto pelo npm quanto por outras ferramentas que podemos usar.

Detalhando as propriedades

Esta seção descreve as propriedades que você pode usar em detalhes. Eu refiro várias vezes a pacote, mas a mesma coisa se aplica a aplicações locais que você não use como pacote. A maioria destas propriedades são usadas somente no site do npm. Outras são usadas por scripts que interagem com seu código, como npm ou outros. name Define o nome do pacote. Ex:

O nome deve ser menor que 214 caracteres, não pode ter espaços e somente pode conter letras minúsculas, hífens (-) ou underscore (_).

Isto tudo porque quando um pacote é publicado no npm, ele ganha sua URL baseado nesta propriedade. Se você publicou este pacote publicamente no GitHub, um bom valor para esta propriedade é o nome do repositório. author Exibe o nome do autor do pacote. Ex:

Também pode ser usado neste formato:

contributors

Assim como o autor, o projeto pode ter um ou mais contribuidores. Esta propriedade é uma array que os lista:

Pode também ser ussado neste formato:

bugs

Links para o issue tracker do pacote, geralmente uma página de issues no GitHub. Ex:

homepage

Define a página inicial do pacote. Ex:

version

Indica a versão atual do pacote. Ex:

Esta propriedade segue a notação semântica de versionamento (semver), o que significa que a versão é sempre expressada com três números: x.x.x.

O primeiro número é a versão principal, o segundo é a versão secundária e o terceiro é a versão do patch.

Existe um significado nestes números: uma release que somente corrija bugs é uma release patch, uma release que introduza mudanças na compatibilidade retroativa é uma release secundária e uma release principal é aquela que pode quebrar compatibilidade.

license Indica a licença do pacote. Ex:

keywords Esta propriedade contém um array ou palavras-chave associados com o que seu pacote faz. Ex:

Isto ajuda as pessoas a encontrar o seu pacote quando estiverem procurando pacotes similares ou quando navegam pelo site do npm.

description

Esta propriedade contém um resumo do pacote. Ex:

Isto é especialmente útil se você decidir publicar seu pacote para o npm, visando que outras pessoas possam descobrir o que este pacote faz.

repository Esta propriedade especifica onde o repositório do pacote está localizado. Ex:

Note o prefixo github. Existem outros serviços populares também:

Você pode explicitamente definir o controle de versão do sistema:

Você também pode usar diferentes sistemas de controle de versão:

main Define o ponto de entrada do pacote. Quando você importa este pacote em uma aplicação, é essa aplicação que a aplicação irá buscar pelo module.exports. Ex:

private Se definido como true, previne que a aplicação/pacote seja acidentalmente publicada no npm. Ex:

scripts Define um conjunto de scripts node que você pode executar. Ex:

Estes scripts são aplicações de linha de comando. Você pode rodá-los usando npm run XXXX, onde XXXX é o nome do comando. Ex:

Você pode usar qualquer nome que você quiser para um comando, e os scripts podem ser literalmente qualquer coisa que você quiser.

dependencies

Define uma lista de pacotes npm instalados como dependências. Quando você instalar um pacote usando npm:

o pacote será automaticamente inserido nesta lista. Exemplo:

devDependencies

Define uma lista de pacotes npm instalados como dependências de desenvolvimento. Eles diferem de dependencies porque eles serão instalados somente em máquinas de desenvolvimento, não necessárias para executar o código em produção.

Quando você instalar um pacote usando npm:

o pacote será automaticamente inserido nessa lista. Exemplo:

engines

Define quais versões de Node.js e outros comandos que este pacote ou aplicação suporta. Exemplo:

browserslist

É usado para dizer quais browsers (e suas versões) você quer suportar. Ele é referenciado pelo Babel, Autoprefixer, e outras ferramentas, para somente adicionar os polyfills e fallbacks necessários aos navegadores-alvo. Exemplo:

Esta configuração significa que você quer suportar ao menos as duas versões principais de todos os browsers com ao menos 1% de uso no mercado (as estatísticas são do CanIUse.com ), exceto IE8 e inferiores (saiba mais no browserslist do NPM).

Comandos específicos de propriedades

O arquivo package.json também pode hospedar configurações de comandos específicos, por exemplo Babel, ESLint, e muito mais.

Cada um possui uma propriedade específica, como eslintConfigbabel e outros. Estes são comandos específicos e você pode encontrar como usá-los na documentação do respectivo comando ou projeto.

Versões de Pacote

Eu já falei sobre isso extensivamente neste artigo aqui.

O arquivo package-lock.json

Na versão 5 o NPM introduziu o arquivo package-lock.json, que é automaticamente gerado quando você instala pacotes Node.

O que ele faz? Você provavelmente sabe tudo sobre o arquivo package.json a essa altura, o que é bem mais comum e está aí há bem mais tempo.

O objetivo deste arquivo é manter registro das versões exatas de cada pacote que é instalado para que um produto possa ser 100% reproduzível da mesma maneira mesmo se os pacotes forem atualizados por seus mantenedores.

Isto soluciona um problema bem específico que o package.json não resolvia. No package.json você pode definir quais versões você quer atualizar, usando a notação semver, por exemplo:

  • se você escrever ~0.13.0, você quer somente atualizar patch releases: 0.13.1 está ok, mas 0.14.0 não.
  • se você escrever ^0.13.0, você quer atualizar patches e minor releases: 0.13.10.14.0 e assim por diante.
  • se você escrevere 0.13.0, você somente usará esta versão exata do pacote.

Você não commita no Git a sua pasta node_modules, uma vez que ela é geralmente muito grande, e quando você tenta replicar o projeto em outra máquina usando o comando npm install, se você especificar a sintaxe ~ e uma patch release de um pacote tiver sido lançada, ela será instalada. O mesmo para  ^ e minor releases.

Se você especificar as versões exatas, como 0.13.0 neste exemplo, você não sofre desse problema.

Além poder ser um problema para você, pode ser um problema para outra pessoa qualquer querendo rodar o seu projeto com npm install, podendo acontecer do seu projeto original ficar diferente da nova instalação. Isto implica obviamente em possíveis bugs, mesmo que seja um patch ou minor release.

O arquivo package-lock.json define as versões instaladas de cada pacote de maneira irreversível e o npm usará exatamente estas versões quando você rodar npm install.

Este conceito não é novo e outros gerenciadores de pacotes de linguagens de programação (como o Composer do PHP) usam um sistema semelhante por anos.

O arquivo package-lock.json precisa ser commitado no Git para que possa ser baixado por outras pessoas. E se precisar atualizar as versões das dependências no package-lock.json, basta rodar npm update.

Espero que este artigo tenha sido útil para você que está aprendendo Node.js Para conteúdo mais aprofundado, recomendo meus livros. Para videoaulas, recomendo o meu curso online.

Curso Node.js e MongoDB
Curso Node.js e MongoDB