---
title: "Como hospedar Spring Boot na VPS com systemd e Nginx"
description: "Hospede Spring Boot na VPS Ubuntu: Java certo, JAR como serviço systemd, heap da JVM ajustado, Nginx com HTTPS, firewall e atualização segura."
url: "https://streethosting.com.br/guias/vps/hospedar-spring-boot-vps"
category: "vps"
slug: "hospedar-spring-boot-vps"
datePublished: "2026-09-28"
dateModified: "2026-09-28"
author: "Equipe StreetHosting"
difficulty: "intermediario"
language: "pt-BR"
keywords:
  - "hospedar spring boot vps"
  - "deploy spring boot ubuntu"
  - "spring boot systemd service"
  - "spring boot nginx proxy reverso"
  - "java jar producao vps"
---

# Spring Boot em produção na VPS: do JAR ao domínio com HTTPS

Uma aplicação Spring Boot vira serviço de produção com poucas peças: Java do sistema, um usuário dedicado, uma unidade systemd e o Nginx na frente. Veja cada passo e como dimensionar a memória da JVM para não ser derrubado pelo sistema.

> **Resposta rápida**
>
> Para **hospedar Spring Boot na VPS**, instale o Java da mesma versão usada no build, copie o JAR executável para `/opt`, rode com um usuário dedicado por meio de uma unidade systemd com reinício automático e limite de heap, e publique pelo Nginx com HTTPS do Let's Encrypt. A aplicação escuta só em 127.0.0.1:8080 e o firewall libera apenas SSH, 80 e 443.

## Como a aplicação fica montada na VPS

O Spring Boot empacota a aplicação e o servidor web em um único JAR. Isso simplifica muito a hospedagem: não há servidor de aplicação para instalar, só o Java. O resto é infraestrutura em volta para manter o processo vivo e exposto com segurança.

| Peça | Função | Porta |
| --- | --- | --- |
| Nginx | Recebe o tráfego, termina o HTTPS e repassa para a aplicação | 80 e 443 públicas |
| Spring Boot (Tomcat embutido) | Executa a aplicação | 8080 só no 127.0.0.1 |
| systemd | Inicia no boot, reinicia se cair, guarda os logs | Nenhuma |
| PostgreSQL ou MySQL | Banco de dados local | 5432 ou 3306 só no 127.0.0.1 |
| UFW | Bloqueia tudo que não for SSH, 80 e 443 | Nenhuma |

Se a aplicação usa banco relacional e ele ainda não existe, instale antes seguindo o guia de [PostgreSQL na VPS Ubuntu](https://streethosting.com.br/guias/vps/instalar-postgresql-vps-ubuntu), que já cria usuário e banco dedicados.

## Instalar o Java certo

Spring Boot 3 e 4 exigem Java 17 ou mais novo. A regra que evita dor de cabeça é simples: a VPS roda a mesma versão major usada para compilar. Confira no projeto a propriedade `java.version` do `pom.xml` ou o toolchain do Gradle. O Ubuntu 24.04 traz as versões 17, 21 e 25 no repositório padrão, então não é preciso adicionar fonte externa.

```
sudo apt update
sudo apt install -y openjdk-21-jre-headless
java -version
```

O pacote `jre-headless` tem só o necessário para executar, sem bibliotecas gráficas. Se você pretende compilar na própria VPS, instale o JDK (`openjdk-21-jdk-headless`). O mais comum, e mais leve para o servidor, é compilar no seu computador ou no CI e enviar só o JAR.

## Gerar o JAR e preparar o servidor

No projeto, gere o JAR executável com o wrapper da ferramenta de build:

```
# Maven: gera target/minha-api-0.0.1-SNAPSHOT.jar
./mvnw clean package -DskipTests

# Gradle: gera build/libs/minha-api-0.0.1-SNAPSHOT.jar
./gradlew bootJar
```

No Gradle, cuidado com o arquivo terminado em `-plain.jar`: ele não tem as dependências e não roda sozinho. O certo é o outro, gerado pela tarefa bootJar.

Na VPS, crie um usuário de sistema sem shell para a aplicação e a pasta onde o JAR vai morar. Rodar como root significa que qualquer falha na aplicação vira controle total do servidor.

```
sudo useradd --system --home-dir /opt/minha-api --shell /usr/sbin/nologin spring
sudo mkdir -p /opt/minha-api /etc/minha-api
sudo chown spring:spring /opt/minha-api
```

Envie o JAR do seu computador e instale com o dono e a permissão certos. O comando `install` copia e ajusta tudo de uma vez. Mais opções de envio, incluindo rsync, estão no guia de [transferir arquivos para a VPS](https://streethosting.com.br/guias/vps/transferir-arquivos-vps-scp-rsync).

```
# no seu computador
scp target/minha-api-0.0.1-SNAPSHOT.jar usuario@IP_DA_VPS:/tmp/app.jar

# na VPS
sudo install -o spring -g spring -m 640 /tmp/app.jar /opt/minha-api/app.jar
sudo -u spring java -jar /opt/minha-api/app.jar --server.address=127.0.0.1
```

Esse teste manual confirma que o JAR sobe com o Java instalado. Quando aparecer no log que o Tomcat iniciou na porta 8080, teste de outro terminal com `curl -i http://127.0.0.1:8080/actuator/health` (se o projeto usa o Actuator) e encerre com Ctrl+C.

## Configuração de produção sem mexer no código

O Spring Boot lê propriedades de variáveis de ambiente convertendo nomes: `server.port` vira `SERVER_PORT`, `spring.datasource.url` vira `SPRING_DATASOURCE_URL`. Isso permite manter senhas fora do repositório, em um arquivo que só o root lê:

```
sudo nano /etc/minha-api/minha-api.env

SPRING_PROFILES_ACTIVE=prod
SERVER_ADDRESS=127.0.0.1
SERVER_PORT=8080
SERVER_FORWARD_HEADERS_STRATEGY=native
SPRING_DATASOURCE_URL=jdbc:postgresql://127.0.0.1:5432/minha_api
SPRING_DATASOURCE_USERNAME=minha_api
SPRING_DATASOURCE_PASSWORD=troque-esta-senha

sudo chmod 600 /etc/minha-api/minha-api.env
```

- **SERVER_ADDRESS=127.0.0.1:** a porta 8080 deixa de existir para a internet. Mesmo que o firewall seja desligado por engano, ninguém de fora acessa a aplicação sem passar pelo Nginx.
- **SERVER_FORWARD_HEADERS_STRATEGY=native:** faz o Tomcat respeitar os cabeçalhos que o Nginx envia com o IP real do visitante e o protocolo original. Sem isso, redirecionamentos saem com http e logs mostram sempre 127.0.0.1.
- **Perfil prod:** ativa o arquivo `application-prod.properties` do projeto, se existir, para desligar recursos de desenvolvimento.

Duas configurações já vêm em bom estado nas versões atuais. O desligamento gracioso é padrão: ao receber o sinal de parada, o servidor para de aceitar conexões novas e termina as que estão em andamento, com prazo de 30 segundos por fase (ajustável em `spring.lifecycle.timeout-per-shutdown-phase`). E o Actuator expõe por HTTP apenas o endpoint de health; se você abrir outros, como métricas ou env, bloqueie o caminho `/actuator` no Nginx.

### Pool de conexões com o banco

O Spring Boot usa o HikariCP como pool de conexões, com no máximo 10 conexões por padrão. O PostgreSQL, por sua vez, aceita 100 conexões simultâneas na configuração padrão. Com uma aplicação só, sobra muito. O problema aparece quando você sobe várias aplicações, ou várias instâncias da mesma, apontando para o mesmo banco: a soma dos pools precisa ficar abaixo do limite do banco, com margem para conexões de manutenção. Ajuste pelo arquivo de ambiente com `SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE`. Aumentar o pool raramente deixa a API mais rápida; em uma VPS com poucos vCPUs, muitas conexões simultâneas só disputam o mesmo processador.

## Serviço systemd e memória da JVM

A unidade systemd faz o papel que um gerenciador de processos faria: sobe no boot, reinicia em caso de falha e manda a saída para o journal.

```
sudo nano /etc/systemd/system/minha-api.service

[Unit]
Description=Minha API Spring Boot
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
User=spring
Group=spring
WorkingDirectory=/opt/minha-api
EnvironmentFile=/etc/minha-api/minha-api.env
ExecStart=/usr/bin/java -Xms256m -Xmx768m -XX:+ExitOnOutOfMemoryError -jar /opt/minha-api/app.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=5
TimeoutStopSec=45

[Install]
WantedBy=multi-user.target
```

O `SuccessExitStatus=143` existe porque a JVM encerra com o código 143 quando recebe o sinal de parada. Sem essa linha, todo `systemctl stop` seria registrado como falha. O `TimeoutStopSec` dá tempo para o desligamento gracioso terminar antes de o systemd forçar.

A opção `-XX:+ExitOnOutOfMemoryError` resolve um problema traiçoeiro. Quando o heap acaba, a JVM não para: ela lança OutOfMemoryError na thread que tentou alocar e segue viva, muitas vezes com pools de conexão ou agendadores quebrados, respondendo erro para uma parte das requisições. Com a opção, o processo encerra na hora e o `Restart=on-failure` sobe uma instância limpa em cinco segundos. Você perde o estado em memória, mas troca uma falha silenciosa por uma que aparece no log.

```
sudo systemctl daemon-reload
sudo systemctl enable --now minha-api
systemctl status minha-api
journalctl -u minha-api -f
```

### Quanto de heap dar para a JVM

Sem `-Xmx`, a JVM usa como teto de heap um quarto da RAM da máquina. Em uma VPS pequena isso pode ser pouco para a aplicação; em uma VPS compartilhada com o banco, pode ser demais somado ao resto. Lembre que o processo Java consome algumas centenas de MB além do heap (metaspace, threads, cache de código), e o banco e o sistema também precisam de espaço. Os valores abaixo são pontos de partida para ajustar depois de medir.

| RAM da VPS | O que roda junto | Heap inicial sugerido |
| --- | --- | --- |
| 2 GB | Só a aplicação | -Xmx768m |
| 4 GB | Aplicação e PostgreSQL | -Xmx1536m |
| 8 GB | Aplicação, banco e Redis | -Xmx3g |
| 16 GB | Duas ou três aplicações e banco | -Xmx3g em cada uma |

> **Atenção**
>
> Se a soma passar da RAM, o kernel escolhe um processo para matar, e costuma ser a JVM, que é o maior. O sintoma é a aplicação reiniciando sozinha sem erro no log dela. Confirme com `sudo dmesg | grep -i kill` e reduza o heap ou aumente a memória.

## Nginx, domínio, HTTPS e firewall

Crie o registro A do domínio, por exemplo um subdomínio para a API, apontando para o IP da VPS, conforme o guia de [apontar domínio para a VPS](https://streethosting.com.br/guias/vps/apontar-dominio-vps-registro-dns). Depois configure o Nginx:

```
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/minha-api

server {
    listen 80;
    listen [::]:80;
    server_name api.seu-dominio.com.br;

    client_max_body_size 20m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        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 $scheme;
        proxy_read_timeout 60s;
    }
}
```

Ative o site, abra só o necessário no firewall e emita o certificado:

```
sudo ln -s /etc/nginx/sites-available/minha-api /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.seu-dominio.com.br
```

Nunca abra a 8080 no firewall. A regra `Nginx Full` libera 80 e 443, que é tudo o que o público precisa. Os detalhes de regras, perfis e como não se trancar fora estão no guia de [firewall UFW](https://streethosting.com.br/guias/vps/firewall-ufw-vps-ubuntu), e a renovação e os cabeçalhos de segurança do HTTPS no guia de [certificado SSL com Nginx](https://streethosting.com.br/guias/vps/certificado-ssl-vps-lets-encrypt-nginx).

> **Dica**
>
> O `client_max_body_size` do Nginx é só metade da conta para uploads. O Spring limita por padrão 1 MB por arquivo e 10 MB por requisição; ajuste `spring.servlet.multipart.max-file-size` e `max-request-size` junto.

## Atualizar a versão e resolver erros comuns

Atualizar é trocar o JAR e reiniciar. Guarde sempre a versão anterior para voltar em segundos se algo der errado:

```
sudo cp /opt/minha-api/app.jar /opt/minha-api/app-anterior.jar
sudo install -o spring -g spring -m 640 /tmp/app.jar /opt/minha-api/app.jar
sudo systemctl restart minha-api
journalctl -u minha-api -n 50 --no-pager
```

Durante a inicialização, que leva de alguns segundos a algumas dezenas de segundos conforme o tamanho da aplicação, o Nginx responde 502. Para eliminar essa janela é preciso rodar duas instâncias em portas diferentes e alternar entre elas no Nginx, o que já é assunto de pipeline. O guia de [deploy com GitHub Actions](https://streethosting.com.br/guias/vps/deploy-github-actions-vps) mostra como automatizar o envio e o reinício.

Os logs da aplicação vão para o journal do systemd, que no Ubuntu fica gravado em disco e sobrevive a reinícios. Para investigar um problema, filtre por período com `journalctl -u minha-api --since "1 hour ago"`. Uma aplicação que registra muito pode encher o disco com o tempo: confira o espaço usado com `journalctl --disk-usage` e, se precisar, defina um teto em `SystemMaxUse=500M` no arquivo `/etc/systemd/journald.conf`, seguido de `sudo systemctl restart systemd-journald`.

| Erro | Causa | Como resolver |
| --- | --- | --- |
| UnsupportedClassVersionError | JAR compilado com Java mais novo que o instalado | Instale a mesma versão major usada no build |
| no main manifest attribute | Rodando o JAR plain em vez do executável | Use o JAR gerado por bootJar ou package do plugin Spring Boot |
| Port 8080 was already in use | Outra instância ou outro serviço na porta | Veja com sudo ss -tlnp e pare o processo antigo |
| Aplicação reinicia sozinha sem erro | Sistema matando a JVM por falta de memória | Confira dmesg e reduza o -Xmx ou aumente a RAM |
| Connection refused ao banco na inicialização | Banco ainda subindo ou escutando em outro endereço | Confira o After= da unidade e o endereço na URL JDBC |
| Redirecionamento para http | Cabeçalhos do proxy ignorados | Defina SERVER_FORWARD_HEADERS_STRATEGY=native |
| 413 Request Entity Too Large | Limite de corpo do Nginx | Aumente client_max_body_size e os limites de multipart |

## Qual VPS escolher para Spring Boot

Aplicações Java pedem duas coisas da VPS. Memória, porque o heap e o overhead da JVM são reservados de uma vez. E CPU rápida, porque a inicialização e a compilação JIT das primeiras requisições são intensas: quanto maior o clock, menor a janela de indisponibilidade a cada deploy. A [VPS Ryzen 9 9950X](https://streethosting.com.br/vps/ryzen), com até 5,7 GHz e DDR5, é a indicação principal. Para vários microsserviços com pools de threads grandes, a [VPS Xeon](https://streethosting.com.br/vps/xeon) entrega mais vCPU por real, com clock menor.

| Cenário | Plano sugerido | Preço mensal |
| --- | --- | --- |
| Uma API com heap até 1,5 GB | Ryzen 2 vCPU, 4 GB DDR5, 40 GB NVMe | R$ 64,00 |
| API e PostgreSQL na mesma VPS | Ryzen 4 vCPU, 8 GB DDR5, 80 GB NVMe | R$ 114,00 |
| Duas ou três aplicações e banco | Ryzen 6 vCPU, 16 GB DDR5, 160 GB NVMe | R$ 214,00 |
| Microsserviços com muitas threads | Xeon 6 vCPU, 8 GB DDR4, 80 GB NVMe | R$ 74,00 |
| Vários serviços Java e banco maior | Xeon 9 vCPU, 16 GB DDR4, 160 GB NVMe | R$ 142,00 |

As duas linhas ficam em São Paulo, com AntiDDoS incluso, disco NVMe, acesso root e ativação em até 60 segundos. Se o consumo da JVM crescer, o upgrade de memória é feito pelo painel, cobra só a diferença proporcional ao ciclo e exige um reinício da VM; depois é só aumentar o `-Xmx` na unidade systemd.

- [ ] Java da mesma versão major usada no build
- [ ] Usuário de sistema dedicado, sem shell
- [ ] Senhas em arquivo de ambiente com permissão 600
- [ ] Aplicação escutando só em 127.0.0.1
- [ ] Unidade systemd com SuccessExitStatus=143, -Xmx e ExitOnOutOfMemoryError
- [ ] Nginx com cabeçalhos Forwarded e HTTPS
- [ ] JAR anterior guardado para rollback

## Perguntas frequentes

### Qual versão do Java usar para Spring Boot?

Spring Boot 3 e 4 exigem Java 17 ou mais novo. Use na VPS a mesma versão major com que o projeto é compilado; o Ubuntu 24.04 oferece as versões 17, 21 e 25 no repositório padrão, e a 21 é uma escolha segura quando não há outra exigência.

### Preciso instalar o Tomcat na VPS?

Não. O JAR executável do Spring Boot já traz o servidor web embutido, Tomcat por padrão. Tomcat instalado à parte só faz sentido para aplicações antigas empacotadas como WAR.

### Quanto de RAM uma aplicação Spring Boot precisa?

Uma API REST pequena costuma rodar bem com heap entre 256 e 768 MB, mas o processo Java usa algumas centenas de MB além do heap. Na prática, 2 GB atendem a aplicação sozinha e 4 GB atendem aplicação e banco na mesma VPS; meça o consumo real depois de alguns dias.

### Posso rodar várias aplicações Spring Boot na mesma VPS?

Pode. Crie uma unidade systemd por aplicação, cada uma escutando em uma porta diferente no 127.0.0.1, e um bloco do Nginx por domínio. A conta que importa é a soma dos heaps mais a sobra de cada JVM, que precisa caber na RAM com folga.

### É melhor usar Docker ou systemd para Spring Boot?

Para um único JAR, systemd é mais simples e não adiciona camada nenhuma. Docker compensa quando você já tem imagem pronta no CI, vários serviços para orquestrar ou quer o mesmo ambiente em qualquer máquina.

## Guias relacionados

- [Como instalar PostgreSQL na VPS Ubuntu com segurança](https://streethosting.com.br/guias/vps/instalar-postgresql-vps-ubuntu.md)
- [Como configurar o Nginx como reverse proxy na VPS](https://streethosting.com.br/guias/vps/configurar-nginx-reverse-proxy-vps.md)
- [UFW na VPS Ubuntu: regras de firewall sem perder o SSH](https://streethosting.com.br/guias/vps/firewall-ufw-vps-ubuntu.md)
- [Como escolher VPS para API: CPU, RAM e conexões](https://streethosting.com.br/guias/vps/escolher-vps-para-api.md)
- [Deploy com GitHub Actions na VPS: pipeline passo a passo](https://streethosting.com.br/guias/vps/deploy-github-actions-vps.md)

## Produtos citados

- https://streethosting.com.br/vps/ryzen
- https://streethosting.com.br/vps/xeon

## Dados estruturados

```json
[
  {
    "@context": "https://schema.org",
    "@type": [
      "Article",
      "TechArticle"
    ],
    "headline": "Spring Boot em produção na VPS: do JAR ao domínio com HTTPS",
    "name": "Como hospedar Spring Boot na VPS com systemd e Nginx",
    "abstract": "Uma aplicação Spring Boot vira serviço de produção com poucas peças: Java do sistema, um usuário dedicado, uma unidade systemd e o Nginx na frente. Veja cada passo e como dimensionar a memória da JVM para não ser derrubado pelo sistema.",
    "description": "Hospede Spring Boot na VPS Ubuntu: Java certo, JAR como serviço systemd, heap da JVM ajustado, Nginx com HTTPS, firewall e atualização segura.",
    "datePublished": "2026-09-28",
    "dateModified": "2026-09-28",
    "author": {
      "@type": "Organization",
      "name": "Equipe StreetHosting"
    },
    "publisher": {
      "@type": "Organization",
      "name": "StreetHosting",
      "url": "https://streethosting.com.br"
    },
    "inLanguage": "pt-BR",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://streethosting.com.br/guias/vps/hospedar-spring-boot-vps"
    }
  },
  {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [
      {
        "@type": "Question",
        "name": "Qual versão do Java usar para Spring Boot?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Spring Boot 3 e 4 exigem Java 17 ou mais novo. Use na VPS a mesma versão major com que o projeto é compilado; o Ubuntu 24.04 oferece as versões 17, 21 e 25 no repositório padrão, e a 21 é uma escolha segura quando não há outra exigência."
        }
      },
      {
        "@type": "Question",
        "name": "Preciso instalar o Tomcat na VPS?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Não. O JAR executável do Spring Boot já traz o servidor web embutido, Tomcat por padrão. Tomcat instalado à parte só faz sentido para aplicações antigas empacotadas como WAR."
        }
      },
      {
        "@type": "Question",
        "name": "Quanto de RAM uma aplicação Spring Boot precisa?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Uma API REST pequena costuma rodar bem com heap entre 256 e 768 MB, mas o processo Java usa algumas centenas de MB além do heap. Na prática, 2 GB atendem a aplicação sozinha e 4 GB atendem aplicação e banco na mesma VPS; meça o consumo real depois de alguns dias."
        }
      },
      {
        "@type": "Question",
        "name": "Posso rodar várias aplicações Spring Boot na mesma VPS?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Pode. Crie uma unidade systemd por aplicação, cada uma escutando em uma porta diferente no 127.0.0.1, e um bloco do Nginx por domínio. A conta que importa é a soma dos heaps mais a sobra de cada JVM, que precisa caber na RAM com folga."
        }
      },
      {
        "@type": "Question",
        "name": "É melhor usar Docker ou systemd para Spring Boot?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Para um único JAR, systemd é mais simples e não adiciona camada nenhuma. Docker compensa quando você já tem imagem pronta no CI, vários serviços para orquestrar ou quer o mesmo ambiente em qualquer máquina."
        }
      }
    ]
  }
]
```
