Criando pacotes .deb para Debian e derivados

Criando pacotes .deb

Distribuir software para Debian, Ubuntu, Mint e derivados sem um .deb é entregar trabalho pela metade: sem gestão de dependências, sem atualização limpa, sem remoção sem rastro. A boa notícia: criar um pacote .deb decente é mais simples do que a fama sugere. Neste guia completo você vai do pacote artesanal com dpkg-deb ao pacote profissional com debhelper, passando por scripts de manutenção, lintian e repositório APT próprio.

Anatomia de um .deb

Um .deb é só um arquivo ar com três membros: debian-binary (versão do formato), control.tar.zst (metadados e scripts) e data.tar.zst (os arquivos que serão instalados, com seus caminhos finais). Dá para inspecionar qualquer pacote do sistema:

ar t /var/cache/apt/archives/htop_*.deb   # lista os 3 membros
dpkg-deb --info htop_*.deb                # metadados (control)
dpkg-deb --contents htop_*.deb            # arquivos e destinos

Método 1: pacote rápido com dpkg-deb

Perfeito para distribuir um binário próprio (um programa em Go, um script) dentro da empresa. Vamos empacotar um utilitário fictício meuapp:

mkdir -p meuapp_1.0.0-1_amd64/{DEBIAN,usr/bin,usr/share/man/man1,etc/meuapp}
cp meuapp meuapp_1.0.0-1_amd64/usr/bin/
gzip -9 -c meuapp.1 > meuapp_1.0.0-1_amd64/usr/share/man/man1/meuapp.1.gz
cp meuapp.conf meuapp_1.0.0-1_amd64/etc/meuapp/

O coração do pacote é o DEBIAN/control:

cat > meuapp_1.0.0-1_amd64/DEBIAN/control << 'EOF'
Package: meuapp
Version: 1.0.0-1
Section: utils
Priority: optional
Architecture: amd64
Depends: libc6 (>= 2.34), ca-certificates
Maintainer: Nilton Oliveira 
Homepage: https://www.linuxpro.com.br
Description: Utilitário de exemplo do LinuxPro
 Linha longa da descrição: cada linha do corpo
 começa com um espaço. Uma linha só com " ." separa parágrafos.
EOF

Arquivos em /etc merecem tratamento de configuração — declarados em conffiles, o dpkg preserva as edições do admin nos upgrades:

echo "/etc/meuapp/meuapp.conf" > meuapp_1.0.0-1_amd64/DEBIAN/conffiles

Precisa criar usuário de sistema ou habilitar um serviço? Entram os scripts de manutenção (preinst, postinst, prerm, postrm), todos executáveis:

cat > meuapp_1.0.0-1_amd64/DEBIAN/postinst << 'EOF'
#!/bin/sh
set -e
if [ "$1" = "configure" ]; then
    getent passwd meuapp >/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin meuapp
fi
EOF
chmod 755 meuapp_1.0.0-1_amd64/DEBIAN/postinst

Gere o pacote (o --root-owner-group dispensa fakeroot) e teste:

dpkg-deb --build --root-owner-group meuapp_1.0.0-1_amd64
sudo apt install ./meuapp_1.0.0-1_amd64.deb   # apt resolve as dependências
dpkg -L meuapp                                # confere o que foi instalado
sudo apt remove meuapp

Método 2: pacote profissional com debhelper

Para publicar de verdade — com changelog, compilação a partir do código-fonte e conformidade com a política Debian — o caminho é o debhelper. Instale a bancada:

sudo apt install build-essential devscripts debhelper dh-make lintian

Na raiz do seu código-fonte (ex.: meuapp-1.0.0/):

cd meuapp-1.0.0
dh_make --single --native --packagename meuapp_1.0.0 --email nilton@example.com
rm debian/*.ex debian/*.EX   # limpa os exemplos

O diretório debian/ gerado tem quatro arquivos essenciais:

  • debian/control — metadados do fonte e dos binários (Build-Depends aqui!)
  • debian/changelog — versão vem daqui; edite com dch -i
  • debian/rules — makefile do build; com debhelper moderno são 4 linhas
  • debian/copyright — licença no formato DEP-5

Um debian/rules típico hoje é só isto (o dh descobre o resto — Makefile, CMake, Go, Python…):

#!/usr/bin/make -f
%:
	dh $@

Se o upstream não tem sistema de build, o debian/install mapeia arquivos para destinos:

echo "meuapp usr/bin" > debian/install
echo "meuapp.conf etc/meuapp" >> debian/install

Tem unit do systemd? Nomeie como debian/meuapp.service e o dh_installsystemd instala, habilita e dá restart no upgrade sozinho. Construa e valide:

dpkg-buildpackage -us -uc -b   # sem assinatura, só binário
lintian ../meuapp_1.0.0_amd64.changes   # o "linter" oficial da política Debian

Trate os avisos do lintian como um code review: cada tag tem explicação com lintian-explain-tags <tag>.

Dependências automáticas

Nunca chute versões de bibliotecas. No debian/control do binário, use as variáveis mágicas — o dpkg-shlibdeps calcula as dependências reais analisando os ELF:

Depends: ${shlibs:Depends}, ${misc:Depends}

Binários Go/Rust estáticos praticamente não têm Depends — uma das razões de eu empacotar minhas ferramentas em Go.

Versões e upgrades

O formato é [epoch:]versão-upstream[-revisão-debian] — ex.: 1.0.0-2 é a segunda revisão do empacotamento da mesma versão 1.0.0. O dpkg compara com dpkg --compare-versions; teste na dúvida:

dpkg --compare-versions 1.0.0-2 lt 1.0.1-1 && echo "upgrade ok"

Repositório APT próprio

Distribuir .deb avulso por download é metade do caminho — o resto é um repositório para apt upgrade funcionar. O jeito moderno e simples com reprepro:

sudo apt install reprepro
mkdir -p /srv/repo/conf
cat > /srv/repo/conf/distributions << 'EOF'
Codename: stable
Suite: stable
Components: main
Architectures: amd64 arm64
SignWith: SEU_KEY_ID_GPG
EOF
reprepro -b /srv/repo includedeb stable meuapp_1.0.0-1_amd64.deb

Sirva /srv/repo com nginx e, no cliente:

curl -fsSL https://repo.example.com/chave.gpg | sudo tee /usr/share/keyrings/meurepo.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/meurepo.gpg] https://repo.example.com stable main" | 
  sudo tee /etc/apt/sources.list.d/meurepo.list
sudo apt update && sudo apt install meuapp

Atalho: fpm

Para uso interno, o fpm gera .deb (e .rpm) de um diretório em um comando — sem política Debian, mas resolve rápido:

gem install fpm
fpm -s dir -t deb -n meuapp -v 1.0.0 --description "Meu utilitário" 
  --depends ca-certificates meuapp=/usr/bin/meuapp

Resumo prático

  • Ferramenta interna? dpkg-deb --build ou fpm — 10 minutos
  • Software publicado? debhelper + lintian limpo + repositório assinado com reprepro
  • Config em /etc sempre em conffiles; usuário de sistema no postinst; unit do systemd via dh_installsystemd

No próximo post desta dupla: o mesmo caminho para a família Red Hat com pacotes .rpm — spec file, rpmbuild, mock e createrepo.