Minimal APIs - Especificar a porta
Definir a porta na Minimal API é uma necessidade frequente quando a aplicação precisa rodar em um ambiente controlado, ao lado de outros serviços ou dentro de um container. Neste guia, você aprende a especificar a porta e a configurar os detalhes do servidor web ao executar aplicações ASP.NET Core no .NET 6.
Por que definir a porta na Minimal API
Tanto o ASP.NET MVC quanto as Minimal APIs permitem configurar os detalhes de execução da aplicação. Entre esses detalhes, o endereço e a porta de escuta estão entre os mais importantes.
Em cenários mais controlados, precisamos executar a aplicação em uma porta específica. Por exemplo, um proxy reverso pode esperar a API sempre na porta 3000, ou outro serviço já pode ocupar a porta padrão.
Além disso, ambientes de nuvem e plataformas de hospedagem costumam informar a porta por meio de variáveis de ambiente. Por isso, saber todas as formas de definir a porta na Minimal API evita conflitos e erros difíceis de diagnosticar.
Se você ainda não criou uma aplicação com esse modelo, o artigo ASP.NET Minimal APIs apresenta a estrutura básica do Program.cs.
Como o ASP.NET Core escolhe a porta por padrão
Quando você cria um projeto com dotnet new ou com o Visual Studio, o template gera o arquivo Properties/launchSettings.json. Esse arquivo define as portas que a aplicação usa durante o desenvolvimento.
Na prática, o dotnet run lê o perfil desse arquivo e aplica a URL configurada nele. Por isso, cada projeto novo costuma subir em uma porta aleatória diferente.
Quando nenhuma configuração existe, o Kestrel, servidor web embutido no ASP.NET Core, escuta em http://localhost:5000. Ou seja, toda porta que você define no código, na linha de comando ou no ambiente substitui esse comportamento padrão.
Atenção ao launchSettings.json no Visual Studio
A documentação oficial faz um alerta importante sobre os exemplos de troca de porta. Ao executá-los pelo Visual Studio, você pode receber a mensagem Unable to connect to web server 'AppName'.
Isso acontece porque o Visual Studio espera a porta indicada no launchSettings.json, enquanto a aplicação passa a escutar em outra porta. Portanto, rode os exemplos deste artigo pela linha de comando, com dotnet run, ou ajuste também o arquivo de perfil.
Especificar a porta na Minimal API pelo método Run
A forma mais direta de fixar a porta na Minimal API é passar a URL de execução para o método Run. Dessa forma, o endereço fica explícito no próprio Program.cs.
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.Run("http://localhost:3000"); // Aqui definimos a URL e a porta
Nesse código, a aplicação responde na porta 3000. Ao acessar http://localhost:3000, o navegador mostra a mensagem Hello World!.
O método Run aceita uma única URL. Assim, ele atende bem aos cenários em que a aplicação escuta apenas um endereço.
Por outro lado, essa abordagem deixa a porta fixa no código. Então, sempre que o ambiente mudar, você precisa alterar o arquivo e publicar de novo.
Especificar várias portas na Minimal API
Da mesma forma, podemos especificar várias portas com o método Urls.Add. Cada chamada acrescenta um endereço à coleção Urls do WebApplication.
Com isso, o servidor passa a escutar em todas as portas especificadas ao mesmo tempo.
var app = WebApplication.Create(args);
// Cada URL adicionada vira um endereço de escuta do Kestrel
app.Urls.Add("http://localhost:3000");
app.Urls.Add("http://localhost:4000");
app.MapGet("/", () => "Hello World");
app.Run();
Repare que, nesse caso, o método Run não recebe parâmetro. Afinal, as URLs já estão registradas na coleção Urls.
Ao executar a aplicação, o console lista cada endereço na mensagem Now listening on. Assim, você confirma que a porta na Minimal API foi aplicada corretamente.
Esse recurso ajuda quando você quer expor HTTP e HTTPS ao mesmo tempo ou atender clientes legados em uma porta antiga. Ainda assim, cada porta extra amplia a superfície de exposição, então abra apenas as necessárias.
Atribuir a porta dinamicamente pela linha de comando
Porém, talvez você queira definir a porta no momento da execução, sem deixá-la no código. Nesse caso, use o parâmetro --urls do dotnet run.
dotnet run --urls="https://localhost:1234"
Esse comando faz a aplicação responder em https://localhost:1234. Além disso, o parâmetro aceita várias URLs separadas por ponto e vírgula.
dotnet run --urls="http://localhost:3000;https://localhost:3001"
O parâmetro funciona porque o WebApplication.Create(args) repassa os argumentos da linha de comando para a configuração. Por isso, não esqueça de manter o args na criação da aplicação.
Essa é uma ótima opção para scripts de execução e pipelines de CI. Afinal, o mesmo código aceita qualquer porta na Minimal API sem nenhuma recompilação.
Existe um detalhe que costuma confundir: se o arquivo appsettings.json também define endpoints do Kestrel, a URL desse arquivo prevalece. Nesse caso, o Kestrel registra um aviso no console informando que vai ignorar os endereços recebidos.
Definir a porta na Minimal API por variável de ambiente
Para finalizar as abordagens do material original, podemos usar variáveis de ambiente. Esse modelo combina com containers e serviços de nuvem, que injetam a configuração no momento da execução.
Lendo a variável PORT
No exemplo a seguir, a aplicação lê a variável PORT com o método Environment.GetEnvironmentVariable. Quando a variável não existe, o código usa a porta 3000 como valor padrão.
var app = WebApplication.Create(args);
// Lê a porta do ambiente; usa 3000 se a variável não existir
var port = Environment.GetEnvironmentVariable("PORT") ?? "3000";
app.MapGet("/", () => "Hello World");
app.Run($"http://localhost:{port}");
Para testar, defina a variável antes de executar a aplicação. No Linux e no macOS, use PORT=5050 dotnet run; no PowerShell, use $env:PORT=5050 e depois dotnet run.
Algumas plataformas de hospedagem informam a porta exatamente por uma variável chamada PORT. Assim, esse padrão facilita a publicação nesses ambientes.
Repare também que o operador ?? garante um valor padrão. Com isso, a porta na Minimal API nunca fica vazia, mesmo quando alguém esquece de configurar o ambiente.
Usando a variável de ambiente do ASP.NET Core
Segundo a documentação de Minimal APIs da Microsoft, a forma preferida de definir a porta pelo ambiente é a variável ASPNETCORE_URLS. A vantagem é que ela dispensa qualquer código de leitura no Program.cs.
ASPNETCORE_URLS=http://localhost:3000
Assim como o parâmetro --urls, a variável aceita múltiplas URLs separadas por ponto e vírgula.
ASPNETCORE_URLS=http://localhost:3000;https://localhost:5000
Dessa forma, o mesmo binário roda em portas diferentes conforme o ambiente. Em outras palavras, a porta na Minimal API deixa de ser uma decisão de código e passa a ser uma decisão de implantação.
Configurar a porta na Minimal API pelo appsettings.json
Além das opções do material original, o Kestrel aceita endpoints declarados no arquivo appsettings.json. Essa abordagem mantém a porta fora do código e, ao mesmo tempo, versionada junto com a aplicação.
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:3000"
},
"Https": {
"Url": "https://localhost:3001"
}
}
}
}
Cada entrada dentro de Endpoints recebe um nome livre e uma URL. Assim, você consegue declarar quantos endereços precisar, cada um com seu próprio esquema.
Como vimos, essa seção vence o parâmetro --urls e a variável de ambiente. Por isso, ela funciona bem como configuração base, enquanto arquivos como appsettings.Production.json ajustam a porta por ambiente.
Usando UseUrls no WebHost
Quando você cria a aplicação com WebApplication.CreateBuilder, também pode definir as URLs pelo método UseUrls da propriedade WebHost. O efeito é parecido com o da coleção Urls, mas a configuração acontece antes do Build.
var builder = WebApplication.CreateBuilder(args);
// Define as URLs de escuta ainda na fase de configuração do host
builder.WebHost.UseUrls("http://localhost:3000", "http://localhost:4000");
var app = builder.Build();
app.MapGet("/", () => "Hello World");
app.Run();
Essa forma é útil quando outras configurações do host também ficam nesse trecho. Contudo, ela continua fixando a porta no código, com as mesmas limitações do método Run.
Porta na Minimal API dentro de containers
Containers são um dos cenários em que a configuração de porta mais causa dúvidas. Afinal, existem duas portas envolvidas: a porta em que a aplicação escuta dentro do container e a porta publicada no host.
Nas imagens oficiais do ASP.NET Core anteriores ao .NET 8, a variável ASPNETCORE_URLS já vinha definida para a porta 80. Portanto, uma aplicação .NET 6 em container escuta na porta 80 por padrão, e você mapeia essa porta com docker run -p 8000:80.
Se a aplicação fixar outra porta no código, o mapeamento precisa acompanhar essa mudança. Caso contrário, o Docker encaminha as requisições para uma porta em que ninguém escuta.
Por isso, em containers, prefira controlar a porta pela variável de ambiente em vez de fixá-la no Program.cs. Dessa forma, a imagem continua a mesma e apenas o comando de execução muda.
Vale registrar que, a partir do .NET 8, a porta padrão das imagens mudou de 80 para 8080. Se você atualizar a versão no futuro, revise os mapeamentos de porta das suas imagens.
Escutar em todas as interfaces de rede
Até aqui, todos os exemplos usaram localhost, que aceita conexões apenas da própria máquina. No entanto, dentro de um container ou em um servidor, a aplicação precisa aceitar conexões externas.
Para isso, troque localhost por *, + ou 0.0.0.0. Os três formatos fazem o Kestrel escutar em todas as interfaces.
Nesse caso, a porta na Minimal API continua a mesma, e muda apenas o conjunto de endereços que aceita conexões.
var app = WebApplication.Create(args);
// Aceita conexões de qualquer interface de rede na porta 3000
app.Urls.Add("http://0.0.0.0:3000");
app.MapGet("/", () => "Hello World");
app.Run();
A mesma ideia vale para a variável de ambiente, como em ASPNETCORE_URLS=http://*:3000;https://+:5000. Contudo, use esse recurso com cuidado, porque ele expõe a aplicação para toda a rede.
Se você pretende rodar a API em container, o artigo Docker: instalação, configuração e primeiros passos ajuda a preparar o ambiente.
Usar HTTPS na porta escolhida
Para escutar em HTTPS, basta informar uma URL com esse esquema. Durante o desenvolvimento, o Kestrel usa o certificado de desenvolvimento do ASP.NET Core.
var app = WebApplication.Create(args);
app.Urls.Add("https://localhost:3000");
app.MapGet("/", () => "Hello World");
app.Run();
Se o navegador não confiar no certificado, execute dotnet dev-certs https --trust no Windows ou no macOS. Assim, o certificado local passa a ser aceito sem alertas.
Em produção, você aponta para um certificado próprio pela seção Kestrel:Certificates:Default do appsettings.json. Essa seção recebe o caminho do arquivo .pem e o da chave privada.
Vale lembrar que HTTP e HTTPS precisam de portas diferentes. Então, quando a aplicação atende os dois esquemas, reserve uma porta na Minimal API para cada um, como 3000 e 3001.
Ordem de prioridade das configurações de porta
Como existem várias formas de definir a porta na Minimal API, vale entender qual vence quando mais de uma aparece ao mesmo tempo. A regra geral segue a ordem de leitura da configuração descrita na documentação de endpoints do Kestrel.
- Endpoints definidos na seção
Kestreldoappsettings.jsonprevalecem sobre--urlseASPNETCORE_URLS. - O parâmetro
--urlsentra pela linha de comando, que tem precedência sobre as variáveis de ambiente. - A variável
ASPNETCORE_URLSvale quando nenhuma das opções anteriores define endereço. - Sem nenhuma configuração, o Kestrel usa
http://localhost:5000.
Portanto, se a porta não mudar como você espera, comece verificando o appsettings.json e o launchSettings.json. Na maioria dos casos, a causa está em um desses dois arquivos.
Outra dica útil é observar a mensagem Now listening on no console. Ela mostra a porta na Minimal API que realmente venceu, independentemente de onde a configuração veio.
Em versões posteriores, a partir do .NET 8, surgiram também as variáveis ASPNETCORE_HTTP_PORTS e ASPNETCORE_HTTPS_PORTS. Elas aceitam apenas números de porta, mas não fazem parte do .NET 6 usado neste artigo.
Erros comuns ao trocar a porta na Minimal API
O erro mais frequente é a porta já estar em uso por outro processo. Nesse caso, a aplicação encerra logo na inicialização com uma mensagem informando que o endereço já está ocupado.
Para descobrir quem ocupa a porta, use lsof -i :3000 no Linux e no macOS. Já no Windows, use netstat -ano | findstr :3000 e localize o identificador do processo.
Outro problema comum surge quando a aplicação roda em container e escuta apenas em localhost. Então, mesmo com a porta publicada, nenhuma requisição externa chega, porque o endereço não inclui as outras interfaces.
Por fim, lembre que portas abaixo de 1024 exigem privilégios elevados em sistemas Linux. Por isso, prefira portas altas, como 3000, 5000 ou 8080, em aplicações que rodam sem permissão de administrador.
Em resumo, quase todo problema com a porta na Minimal API envolve conflito de processo, endereço restrito ou configuração sobrescrita. Assim, verificar esses três pontos resolve a maior parte dos casos.
Conclusão sobre a porta na Minimal API
Você viu quatro formas principais de definir a porta na Minimal API: o método Run, a coleção Urls, o parâmetro --urls e as variáveis de ambiente. Cada uma atende a um momento diferente do ciclo de vida da aplicação.
Para testes rápidos, o Run com URL fixa resolve. Já para ambientes reais, a configuração externa, por linha de comando ou ambiente, traz mais flexibilidade e evita publicações desnecessárias.
Com essas técnicas, você controla com precisão onde a aplicação escuta. Além disso, entende por que uma porta às vezes não muda e como corrigir o problema rapidamente.
FAQ
Qual a porta padrão de uma Minimal API no .NET 6?
Sem configuração, o Kestrel escuta em http://localhost:5000. Projetos criados pelo template, porém, usam as portas definidas no launchSettings.json.
Posso usar mais de uma porta na mesma aplicação?
Sim, basta chamar app.Urls.Add para cada endereço ou separar as URLs por ponto e vírgula. O servidor passa a escutar em todas elas.
Por que o parâmetro --urls não mudou a porta?
Provavelmente o appsettings.json define endpoints na seção Kestrel, que prevalecem. Verifique também se o código usa WebApplication.Create(args).
Qual a diferença entre localhost e 0.0.0.0?
O localhost aceita conexões apenas da própria máquina. Já o 0.0.0.0 aceita conexões de todas as interfaces de rede.
Qual variável de ambiente devo usar para a porta?
A documentação recomenda ASPNETCORE_URLS, que não exige código extra. A variável PORT exige leitura manual com Environment.GetEnvironmentVariable.