{"id":692,"date":"2026-09-06T14:47:34","date_gmt":"2026-09-06T17:47:34","guid":{"rendered":"https:\/\/www.linuxpro.com.br\/2026\/09\/criando-pacotes-rpm\/"},"modified":"2026-09-08T09:03:57","modified_gmt":"2026-09-08T12:03:57","slug":"criando-pacotes-rpm","status":"publish","type":"post","link":"https:\/\/www.linuxpro.com.br\/en\/2026\/09\/criando-pacotes-rpm\/","title":{"rendered":"Criando pacotes .rpm para a fam\u00edlia Red Hat"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"Mascote do LinuxPro colocando o software dentro de uma caixa marcada com o chap\u00e9u vermelho, na esteira de empacotamento\" src=\"\/wp-content\/uploads\/2026\/09\/pacotes-rpm-v3.webp\" width=\"1486\" height=\"856\" \/><\/p>\n<p>Na <a href=\"\/2026\/09\/criando-pacotes-deb\/\">primeira parte desta dupla<\/a> montamos pacotes .deb para Debian e Ubuntu. Agora \u00e9 a vez da fam\u00edlia Red Hat \u2014 RHEL, Fedora, Rocky, AlmaLinux, e por tabela openSUSE: vamos criar pacotes <strong>.rpm<\/strong> do zero, do spec file ao reposit\u00f3rio <code>dnf<\/code> pr\u00f3prio, passando por rpmbuild, rpmlint, mock e assinatura GPG.<\/p>\n<h2>Como o RPM funciona<\/h2>\n<p>Diferente do .deb (um diret\u00f3rio que voc\u00ea monta na m\u00e3o), o mundo RPM gira em torno de um \u00fanico arquivo-receita: o <strong>spec file<\/strong>. Ele descreve metadados, depend\u00eancias, como compilar, o que instalar e o changelog \u2014 e o <code>rpmbuild<\/code> faz o resto. Para inspecionar qualquer pacote:<\/p>\n<pre><code class=\"language-bash\">rpm -qip htop-*.rpm      # metadados\nrpm -qlp htop-*.rpm      # lista de arquivos\nrpm -q --scripts htop    # scripts de instala\u00e7\u00e3o de um pacote instalado<\/code><\/pre>\n<h2>Preparando a bancada<\/h2>\n<pre><code class=\"language-bash\"># Fedora \/ RHEL \/ Rocky \/ Alma\nsudo dnf install rpm-build rpmdevtools rpmlint\n\n# cria a \u00e1rvore de trabalho em ~\/rpmbuild\nrpmdev-setuptree\ntree ~\/rpmbuild\n# BUILD\/ BUILDROOT\/ RPMS\/ SOURCES\/ SPECS\/ SRPMS\/<\/code><\/pre>\n<p>Regra de ouro: <strong>nunca<\/strong> rode <code>rpmbuild<\/code> como root \u2014 um <code>%install<\/code> mal escrito pode escrever no sistema de verdade.<\/p>\n<h2>O spec file, se\u00e7\u00e3o por se\u00e7\u00e3o<\/h2>\n<p>Gere um esqueleto e vamos preencher (<code>meuapp<\/code> de novo como exemplo):<\/p>\n<pre><code class=\"language-bash\">cd ~\/rpmbuild\/SPECS\nrpmdev-newspec meuapp<\/code><\/pre>\n<pre><code class=\"language-bash\">Name:           meuapp\nVersion:        1.0.0\nRelease:        1%{?dist}\nSummary:        Utilit\u00e1rio de exemplo do LinuxPro\n\nLicense:        MIT\nURL:            https:\/\/www.linuxpro.com.br\nSource0:        %{name}-%{version}.tar.gz\n\nBuildRequires:  gcc, make\nRequires:       ca-certificates\n\n%description\nDescri\u00e7\u00e3o longa do pacote. Pode ter v\u00e1rios\npar\u00e1grafos, sem a regra do espa\u00e7o do Debian.\n\n%prep\n%setup -q                # desempacota o Source0 em BUILD\/\n\n%build\nmake %{?_smp_mflags}     # compila com paralelismo\n\n%install\nrm -rf %{buildroot}\ninstall -D -m 0755 meuapp %{buildroot}%{_bindir}\/meuapp\ninstall -D -m 0644 meuapp.conf %{buildroot}%{_sysconfdir}\/meuapp\/meuapp.conf\ninstall -D -m 0644 meuapp.1 %{buildroot}%{_mandir}\/man1\/meuapp.1\n\n%files\n%license LICENSE\n%{_bindir}\/meuapp\n%config(noreplace) %{_sysconfdir}\/meuapp\/meuapp.conf\n%{_mandir}\/man1\/meuapp.1*\n\n%changelog\n* Sat Sep 06 2026 Nilton Oliveira <nilton@example.com> - 1.0.0-1\n- Primeira versao do pacote<\/code><\/pre>\n<p>Pontos que valem destacar:<\/p>\n<ul>\n<li><code>%{?dist}<\/code> no Release vira <code>.el9<\/code>, <code>.fc42<\/code> etc. \u2014 o mesmo spec serve para v\u00e1rias distros<\/li>\n<li><code>%config(noreplace)<\/code> \u00e9 o <code>conffiles<\/code> do mundo RPM: upgrade n\u00e3o sobrescreve a config editada (a nova chega como <code>.rpmnew<\/code>)<\/li>\n<li>Use sempre as macros de caminho (<code>%{_bindir}<\/code>, <code>%{_sysconfdir}<\/code>, <code>%{_unitdir}<\/code>) em vez de caminhos fixos<\/li>\n<li>Tudo que o <code>%install<\/code> criar <strong>precisa<\/strong> estar listado em <code>%files<\/code> \u2014 sobras causam erro de build (de prop\u00f3sito)<\/li>\n<\/ul>\n<h2>Construindo o pacote<\/h2>\n<pre><code class=\"language-bash\"># fonte na pasta certa\ntar czf ~\/rpmbuild\/SOURCES\/meuapp-1.0.0.tar.gz meuapp-1.0.0\/\n\n# build completo: bin\u00e1rio + source RPM\nrpmbuild -ba ~\/rpmbuild\/SPECS\/meuapp.spec\n\nls ~\/rpmbuild\/RPMS\/x86_64\/   # meuapp-1.0.0-1.el9.x86_64.rpm\nls ~\/rpmbuild\/SRPMS\/         # meuapp-1.0.0-1.el9.src.rpm<\/code><\/pre>\n<p>Instale e valide com o rpmlint (o &#8220;lintian&#8221; do RPM):<\/p>\n<pre><code class=\"language-bash\">rpmlint ~\/rpmbuild\/RPMS\/x86_64\/meuapp-*.rpm\nsudo dnf install ~\/rpmbuild\/RPMS\/x86_64\/meuapp-1.0.0-1.el9.x86_64.rpm\nrpm -ql meuapp\nsudo dnf remove meuapp<\/code><\/pre>\n<h2>Scripts de instala\u00e7\u00e3o e usu\u00e1rio de sistema<\/h2>\n<p>Os equivalentes do postinst\/prerm s\u00e3o <code>%pre<\/code>, <code>%post<\/code>, <code>%preun<\/code> e <code>%postun<\/code>. Um usu\u00e1rio de sistema, por exemplo:<\/p>\n<pre><code class=\"language-bash\">%pre\ngetent passwd meuapp >\/dev\/null || \n  useradd --system --no-create-home --shell \/sbin\/nologin meuapp\nexit 0<\/code><\/pre>\n<p>Servi\u00e7o systemd tem macros prontas \u2014 instale a unit em <code>%{_unitdir}<\/code> e use:<\/p>\n<pre><code class=\"language-bash\">BuildRequires: systemd-rpm-macros\n\n%post\n%systemd_post meuapp.service\n\n%preun\n%systemd_preun meuapp.service\n\n%postun\n%systemd_postun_with_restart meuapp.service<\/code><\/pre>\n<h2>Depend\u00eancias autom\u00e1ticas<\/h2>\n<p>O RPM escaneia os bin\u00e1rios sozinho: bibliotecas linkadas viram <code>Requires<\/code> automaticamente (ex.: <code>libssl.so.3()(64bit)<\/code>). Voc\u00ea declara na m\u00e3o s\u00f3 o que ele n\u00e3o enxerga \u2014 bin\u00e1rios chamados via <code>exec<\/code>, arquivos de dados, etc. Bin\u00e1rios Go\/Rust est\u00e1ticos passam quase sem depend\u00eancias.<\/p>\n<h2>Build limpo com mock<\/h2>\n<p>Compilar na sua m\u00e1quina &#8220;suja&#8221; esconde depend\u00eancias de build faltantes. O <code>mock<\/code> constr\u00f3i o pacote num chroot descart\u00e1vel da distro-alvo \u2014 \u00e9 assim que o Fedora\/EPEL constr\u00f3i tudo:<\/p>\n<pre><code class=\"language-bash\">sudo dnf install mock\nsudo usermod -aG mock $USER && newgrp mock\nmock -r rocky-9-x86_64 ~\/rpmbuild\/SRPMS\/meuapp-1.0.0-1.el9.src.rpm\n# resultado em \/var\/lib\/mock\/rocky-9-x86_64\/result\/<\/code><\/pre>\n<p>Com um SRPM e o mock, voc\u00ea gera o mesmo pacote para Rocky 9, Fedora 42 e openSUSE trocando s\u00f3 o <code>-r<\/code>.<\/p>\n<h2>Assinatura GPG<\/h2>\n<pre><code class=\"language-bash\">gpg --gen-key   # se ainda n\u00e3o tem chave\necho \"%_gpg_name Nilton Oliveira <nilton@example.com>\" >> ~\/.rpmmacros\nrpm --addsign ~\/rpmbuild\/RPMS\/x86_64\/meuapp-*.rpm\nrpm -K ~\/rpmbuild\/RPMS\/x86_64\/meuapp-*.rpm   # verifica<\/code><\/pre>\n<h2>Reposit\u00f3rio dnf pr\u00f3prio<\/h2>\n<pre><code class=\"language-bash\">sudo dnf install createrepo_c\nmkdir -p \/srv\/repo\/el9\/x86_64\ncp ~\/rpmbuild\/RPMS\/x86_64\/*.rpm \/srv\/repo\/el9\/x86_64\/\ncreaterepo_c \/srv\/repo\/el9\/x86_64\/<\/code><\/pre>\n<p>Sirva com nginx e, no cliente, um <code>.repo<\/code> resolve:<\/p>\n<pre><code class=\"language-bash\">cat | sudo tee \/etc\/yum.repos.d\/meurepo.repo << 'EOF'\n[meurepo]\nname=Meu Repositorio\nbaseurl=https:\/\/repo.example.com\/el9\/$basearch\/\nenabled=1\ngpgcheck=1\ngpgkey=https:\/\/repo.example.com\/chave.gpg\nEOF\nsudo dnf install meuapp<\/code><\/pre>\n<p>Publicou pacote novo? Rode <code>createrepo_c --update<\/code> e os clientes recebem via <code>dnf upgrade<\/code>.<\/p>\n<h2>Atalho: fpm<\/h2>\n<p>O mesmo <a href=\"https:\/\/fpm.readthedocs.io\/\" rel=\"noopener\" target=\"_blank\">fpm<\/a> do post anterior tamb\u00e9m cospe RPM \u2014 para ferramenta interna, resolve em um comando:<\/p>\n<pre><code class=\"language-bash\">fpm -s dir -t rpm -n meuapp -v 1.0.0 --description \"Meu utilit\u00e1rio\" \n  --depends ca-certificates meuapp=\/usr\/bin\/meuapp<\/code><\/pre>\n<h2>Resumo pr\u00e1tico<\/h2>\n<ul>\n<li><strong>Ferramenta interna?<\/strong> <code>fpm<\/code> ou um spec m\u00ednimo \u2014 r\u00e1pido e suficiente<\/li>\n<li><strong>Publicando de verdade?<\/strong> spec completo + <code>rpmlint<\/code> limpo + build no <code>mock<\/code> + RPM assinado + reposit\u00f3rio com <code>createrepo_c<\/code><\/li>\n<li>Config com <code>%config(noreplace)<\/code>, systemd com as macros <code>%systemd_*<\/code>, caminhos sempre via macros<\/li>\n<\/ul>\n<p>Com os dois posts da dupla \u2014 <a href=\"\/2026\/09\/criando-pacotes-deb\/\">.deb<\/a> e .rpm \u2014 voc\u00ea cobre praticamente todo servidor Linux em produ\u00e7\u00e3o. D\u00favidas ou um caso cabeludo de empacotamento? Me chame na <a href=\"\/contato\/\">p\u00e1gina de contato<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Na primeira parte desta dupla montamos pacotes .deb para Debian e Ubuntu. Agora \u00e9 a vez da fam\u00edlia Red Hat \u2014 RHEL, Fedora, Rocky, AlmaLinux, e por tabela openSUSE: vamos criar pacotes .rpm do zero, do spec file ao reposit\u00f3rio dnf pr\u00f3prio, passando por rpmbuild, rpmlint, mock e assinatura GPG. Como o RPM funciona Diferente &#8230; <a title=\"Criando pacotes .rpm para a fam\u00edlia Red Hat\" class=\"read-more\" href=\"https:\/\/www.linuxpro.com.br\/en\/2026\/09\/criando-pacotes-rpm\/\" aria-label=\"Read more about Criando pacotes .rpm para a fam\u00edlia Red Hat\">Read more<\/a><\/p>","protected":false},"author":0,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[33,2,83],"tags":[337,340,336,339,338,341],"class_list":["post-692","post","type-post","status-publish","format-standard","hentry","category-howtos","category-linux","category-opensuse","tag-empacotamento","tag-fedora","tag-pacotes","tag-redhat","tag-rpm","tag-rpmbuild"],"_links":{"self":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/692","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/comments?post=692"}],"version-history":[{"count":4,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/692\/revisions"}],"predecessor-version":[{"id":1208,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/posts\/692\/revisions\/1208"}],"wp:attachment":[{"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/media?parent=692"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/categories?post=692"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.linuxpro.com.br\/en\/wp-json\/wp\/v2\/tags?post=692"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}