← Voltar para o Blog

chmod 777 não é solução: permissões no Linux, na prática

Todo tutorial de fórum termina em chmod -R 777. Ele faz o erro sumir e deixa o servidor aberto. Este é o modelo mental que faz você acertar a permissão de primeira.

Equipe EasyOps Cloud · · 7 min de leitura

Permission denied. Você pesquisa, o primeiro resultado manda rodar chmod -R 777, o erro some e a aplicação volta. Funcionou — e agora qualquer processo do servidor, incluindo um que entre por uma falha da sua aplicação, pode reescrever esses arquivos.

O 777 é sedutor porque acerta por eliminação: ele libera tudo, então necessariamente inclui a permissão que faltava. O custo é que você nunca descobre qual era.

Os três grupos e as três letras

Toda permissão no Linux responde a duas perguntas: quem e o quê.

O "quem" tem exatamente três faixas:

  • user (u) — o dono do arquivo.
  • group (g) — o grupo do arquivo.
  • other (o) — todo o resto do sistema.

O "o quê" tem três letras, e o valor numérico de cada uma é o que aparece no chmod:

LetraValorEm arquivoEm diretório
r4ler o conteúdolistar os nomes dentro
w2alterar o conteúdocriar e apagar entradas
x1executaratravessar, acessar o que está dentro

A coluna da direita é a parte que quase todo mundo aprende errado. Em diretório as letras significam outra coisa, e é daí que vem a maior parte da confusão.

Um diretório com r e sem x permite listar os nomes e não permite abrir nenhum deles. Um diretório com x e sem r permite abrir um arquivo cujo caminho você já conhece e não permite descobrir o que existe ali. E w em diretório é a permissão de apagar os arquivos de dentro — mesmo os que pertencem a outro usuário, mesmo os marcados como somente leitura. Quem controla quem pode apagar /var/www/html/index.php é a permissão de /var/www/html, não a do arquivo.

Lendo o ls -l sem decorar

ls -l /var/www/html
drwxr-xr-x  3 www-data www-data 4096 ago  6 10:12 uploads
-rw-r-----  1 www-data www-data  812 ago  6 10:12 config.php

O primeiro caractere é o tipo (d diretório, - arquivo comum, l link). Os nove seguintes são três blocos de rwx: dono, grupo, outros. Depois vêm o dono e o grupo.

Somando os valores por bloco, rwxr-xr-x é 755 e rw-r----- é 640.

Na dúvida, o stat responde nos dois formatos de uma vez:

stat -c '%a %U:%G %n' config.php

Os números que você realmente vai usar

Para a esmagadora maioria dos casos, quatro valores bastam:

  • 644 — arquivo comum. O dono edita, o resto lê. É o padrão de código, configuração pública, HTML, imagem.
  • 755 — diretório, ou script executável. O dono altera, os demais entram e leem.
  • 640 / 750 — quando "os demais" não deveriam nem ler. É o valor certo para arquivo com credencial, e 600 quando nem o grupo precisa.
  • 600 — chave privada. O SSH recusa a chave se ela for mais aberta que isso, e faz muito bem — é o motivo de metade dos erros ao usar chaves SSH em vez de senha.

Repare que x não aparece em arquivo comum. Um .php, um .env ou um .jpg não precisam ser executáveis, e marcar tudo como executável de uma vez é outro efeito colateral do chmod -R 777.

Quase sempre o problema é o dono, não a permissão

Este é o ponto que muda a forma de resolver: Permission denied costuma significar que o processo certo não é o dono, não que a permissão está apertada demais.

O nginx roda como www-data, o PHP-FPM como www-data, o PostgreSQL como postgres, a sua aplicação Node como o usuário do User= na unit do systemd. Se os arquivos pertencem ao root porque você fez o deploy com sudo, a aplicação não escreve — e a correção é ajustar o dono:

sudo chown -R www-data:www-data /var/www/html/uploads
sudo find /var/www/html -type d -exec chmod 755 {} +
sudo find /var/www/html -type f -exec chmod 644 {} +

Os dois find fazem o que chmod -R 755 não faz: aplicam 755 só em diretórios e 644 só em arquivos. Um -R com valor único inevitavelmente erra um dos dois lados.

Para descobrir com que usuário um serviço roda:

systemctl show nginx -p User
ps -eo user,comm | grep -E 'nginx|php-fpm|node'

Quando duas contas precisam do mesmo diretório

O caso comum: você faz deploy com seu usuário e o servidor web precisa ler — ou escrever — no mesmo lugar. A resposta é grupo compartilhado, não 777.

sudo usermod -aG www-data deploy
sudo chown -R deploy:www-data /var/www/html
sudo chmod -R g+rwX /var/www/html
sudo chmod g+s /var/www/html

Duas sutilezas valiosas nesse bloco:

  • X maiúsculo aplica x apenas onde ele faz sentido: diretórios e arquivos que já eram executáveis. É a forma correta de usar -R sem transformar todo arquivo em executável.
  • g+s (setgid) faz todo arquivo novo criado ali herdar o grupo do diretório. Sem isso, o próximo arquivo que o deploy criar nasce com o grupo deploy e o servidor web perde o acesso de novo — motivo pelo qual a permissão "volta a quebrar sozinha" depois de cada deploy.

Depois de usermod -aG, o usuário precisa abrir uma sessão nova para o grupo valer. Confirme com id deploy.

umask: por que o arquivo novo já nasce assim

Arquivo novo não nasce 777. O sistema aplica uma máscara que subtrai permissões:

umask        # normalmente 022

Com 022, arquivos nascem 644 e diretórios 755. É por isso que o arquivo que seu script acabou de criar não é gravável pelo grupo mesmo com o diretório configurado — a máscara tirou. Para um processo específico, ajuste o UMask= na unit do systemd em vez de mexer no valor global:

[Service]
UMask=0002

ACL: quando o modelo de três faixas não chega

Dono, grupo e outros dão conta de quase tudo. Quando não dão — dois grupos com níveis diferentes no mesmo diretório, por exemplo — a saída não é abrir para "outros", é usar ACL:

sudo setfacl -m g:auditoria:rx /var/log/meuapp
sudo setfacl -d -m g:auditoria:rx /var/log/meuapp   # vale para arquivos futuros
getfacl /var/log/meuapp

O -d define a ACL padrão, que é o equivalente do setgid para permissões: sem ele, você acerta os arquivos de hoje e erra os de amanhã.

Um + no fim do ls -l (-rw-rwxr--+) indica que o arquivo tem ACL. Se as permissões parecem certas e o acesso não bate, getfacl costuma explicar.

O caso especial: /tmp e o sticky bit

ls -ld /tmp
drwxrwxrwt  15 root root 4096 ago  6 10:12 /tmp

O t final é o sticky bit. Ele existe justamente para consertar o efeito colateral do 777 em diretório: com ele, qualquer um cria arquivo ali, mas só o dono do arquivo pode apagá-lo. É a prova de que "todo mundo pode escrever" e "todo mundo pode destruir" precisaram ser separados.

O checklist para quando aparecer Permission denied

  1. Quem está tentando? systemctl show <unit> -p User, ou o usuário do processo no ps.
  2. Qual arquivo, exatamente? A mensagem quase sempre diz. Se não disser, o strace -f -e trace=file mostra a chamada que falhou.
  3. Ele consegue atravessar o caminho todo? namei -l /var/www/html/uploads/foo.txt imprime a permissão de cada nível. Um diretório sem x no meio do caminho bloqueia tudo abaixo, mesmo com o arquivo final aberto.
  4. É dono ou é permissão? chown resolve o primeiro caso, chmod o segundo. Nesta ordem.
  5. Nada bate? Procure SELinux ou AppArmor: sudo ausearch -m avc -ts recent, ou sudo dmesg | grep -i denied.

Antes de sair distribuindo chmod em produção

Uma alteração recursiva de permissão é fácil de fazer e difícil de desfazer — não existe "desfazer" para um chmod -R que passou por cima de milhares de arquivos com valores diferentes. Tire um snapshot antes, ou pelo menos guarde o estado atual para poder reconstruir:

getfacl -R /var/www > /root/permissoes-var-www.acl
# para restaurar:
setfacl --restore=/root/permissoes-var-www.acl

E se o servidor está exposto à internet, a permissão de arquivo é a segunda camada. A primeira é não deixar a porta aberta: veja como configurar regras de firewall.

Suba um servidor em minutos

Preço em real, suporte em português e dados no Brasil.

Criar conta