segunda-feira, 8 de setembro de 2025

Broadcom Raid

 Tenho 2 servidores DELL e preciso olhar como esta a saúde do RAID e dos discos.

Baixei o STORCLI_SAS3.5_P36 de https://www.broadcom.com/support/download-search?dk=storcli

wget https://docs.broadcom.com/docs-and-downloads/host-bus-adapters/host-bus-adapters-common-files/sas_sata_nvme_12g_p36/STORCLI_SAS3.5_P36.zip


descompactei e na pasta ubuntu tem um .deb

unzip STORCLI_SAS3.5_P36.zip

cd STORCLI_SAS3.5_P36/univ_viva_cli_rel/Unified_storcli_all_os/Ubuntu/

dpkg -i storcli_007.3503.0000.0000_all.deb


Foi necessário criar um link simbolico para executar o comando de forma mais comoda.

ln -s /opt/MegaRAID/storcli/storcli64 /usr/local/bin/storcli


Alguns comandos uteis:

storcli show
storcli /c0/vall show
storcli /c0/eall/sall show
storcli /c0 show all

Para saber o nome do seu servidor também tem um comando interessante:

dmidecode -s system-product-name


Para saber detalhes dos discos físicos:

smartctl -a /dev/sda -d megaraid,0
smartctl -a /dev/sda -d megaraid,1
smartctl -a /dev/sda -d megaraid,2
smartctl -a /dev/sda -d megaraid,3

terça-feira, 2 de setembro de 2025

DNS Seguro e Safe-Search - Restringindo a internet de forma simples

Controles de DNS na Ludicando

Na Ludicando alguns controles eu faço no Mikrotik usando DNS restritivo e alterando alguns domínios para não responder e outros para tratarem o conteúdo para ser seguro para crianças.

Abaixo o link para o script (com comentários citando as fontes de cada produto):
https://gist.github.com/eduardomazolini/77466da39e7940b7d652b2bb5af6ef55

Serviços de DNS confiáveis/populares

OpenDNS

IPv4
208.67.222.222
208.67.220.220

IPv6
2620:119:35::35
2620:119:53::53

DoH
https://doh.opendns.com/dns-query

OpenDNS — Family Shield

IPv4
208.67.222.123
208.67.220.123

DoH
https://doh.familyshield.opendns.com/dns-query

Cloudflare

IPv4
1.1.1.1
1.0.0.1

IPv6
2606:4700:4700::1111
2606:4700:4700::1001

DoH
https://cloudflare-dns.com/dns-query

Cloudflare — Block malware

IPv4
1.1.1.2
1.0.0.2

IPv6
2606:4700:4700::1112
2606:4700:4700::1002

DoH
https://security.cloudflare-dns.com

Cloudflare — Block malware and adult content

IPv4
1.1.1.3
1.0.0.3

IPv6
2606:4700:4700::1113
2606:4700:4700::1003

DoH
https://family.cloudflare-dns.com
https://one.one.one.one/dns-query?name=cloudflare.com

Docs
https://developers.cloudflare.com/1.1.1.1/encryption/

Google Public DNS

IPv4
8.8.8.8
8.8.4.4

IPv6
2001:4860:4860::8888
2001:4860:4860::8844

DoH
https://dns.google/dns-query  (RFC 8484 - GET e POST)
https://dns.google/resolve?    (API JSON - GET)

Docs
https://developers.google.com/speed/public-dns/docs/doh?hl=pt-br

AdGuard DNS — Servidores padrão

AdGuard DNS bloqueará anúncios e rastreadores.

IPv4
94.140.14.14
94.140.15.15

IPv6
2a10:50c0::ad1:ff
2a10:50c0::ad2:ff

DoH
https://dns.adguard-dns.com/dns-query

Página
https://adguard-dns.io/pt_br/public-dns.html

AdGuard DNS — Servidores sem filtragem

IPv4
94.140.14.140
94.140.14.141

IPv6
2a10:50c0::1:ff
2a10:50c0::2:ff

DoH
https://unfiltered.adguard-dns.com/dns-query

AdGuard DNS — Proteção familiar

Bloqueia anúncios, rastreadores, conteúdo adulto e ativa a Pesquisa Segura / Modo seguro quando possível.

IPv4
94.140.14.15
94.140.15.16

IPv6
2a10:50c0::bad1:ff
2a10:50c0::bad2:ff

DoH
https://family.adguard-dns.com/dns-query

Referência adicional

Admin Console Google Workspace (suporte)
https://support.google.com/a/answer/6214622

Wake on Lan - Debian

Para ativar os PCs que suspenderam por tempo e ter acesso remoto.

1) Instalar o ethtool

sudo apt update
sudo apt install ethtool

2) listar as interfaces

ip addr

No meu caso identifiquei enp2s0

3) Crie o arquivo de serviço como root

sudo nano /etc/systemd/system/wol@.service

4) coloque o conteúdo

[Unit]
Description=Wake-on-LAN para %i
After=network.target suspend.target hibernate.target

[Service]
Type=oneshot
ExecStart=/sbin/ethtool -s %i wol g

[Install]
WantedBy=multi-user.target suspend.target hibernate.target

5) Ative o serviço e desta vez observe que o nome do serviço contém a interface

sudo systemctl enable wol@enp2s0.service

sexta-feira, 29 de agosto de 2025

Epson L1800 - CUPS Linux

Infelizmente a Epson não tem drive para ARM nem para sistema de 32bits i386. Pq eu queria usar minha OrangePi ou RapsbarryPi como servidor de impressão. Também tentei deixar um netbook Atom antigo que é 32Bits.

No fim tive que deixar um notebook Positivo de 32G de disco e 1Gb de RAM.

wget https://download3.ebz.epson.net/dsc/f/03/00/15/64/76/69bb3d019d2d4a6b1eeab2fbe4db5c081d2b6b86/epson-inkjet-printer-201312w_1.0.1-1_amd64.deb

apt install cups

apt install printer-driver-gutenprint printer-driver-foo2zjs printer-driver-ptouch ghostscript cups-filters libcupsimage2

apt install ./epson-inkjet-printer-201312w_1.0.1-1_amd64.deb


Esses pacotes acima resolvem erros como:

Filter failed


EPSON_L1800_Series: error while loading shared libraries: libcupsimage.so.2: cannot open shared object file: No such file or directory

PID 0000 (/usr/lib/cups/filter/gstoraster) exited with no errors.


Para acessar remotamente edite:
 

/etc/cups/cupsd.conf

Comente:

#Listen localhost:631

adicione:
Port 631


Procure os blocos <Location />, <Location /admin>, e <Location /admin/conf> e adicione as linhas abaixo dentro de cada bloco:

Allow @LOCAL


Ative o serviço:

sudo systemctl enable cups
sudo systemctl start cups


Se precisar reinicie o serviço:

sudo systemctl restart cups

 

Adicione seu usuário como autorizado:
 

sudo usermod -aG lpadmin $(whoami)

FONTE: https://download.ebz.epson.net/dsc/search/01/search/

O site da Epson em português não tem drive para Linux.

sábado, 16 de agosto de 2025

PIX com TAG NFC

Fazer um pix parece muito fácil não é?

  1. Destravar o celular com Biometria
  2. Tem que achar o app do banco
  3. Logar no app com senha do app
  4. Ir na área de pix
  5. Escolher pagar pix com QR-Code
  6. Mirar a câmera no QR-Code
  7. Aguardar o foco da câmera funcionar
  8. Fazer alguns passos de confirmação
  9. Digitar sua senha de pagamento

Nesse processo você digitou no meio da rua 2 senhas do seu banco.

Eu prefiro pagar com débito:

  1. Destravar o celular com Biometria
  2. Encostar o celular

Mas se der para fazer PIX por aproximação?

  1. Destravar o celular com Biometria
  2. Encostar o celular
  3. Digitar o valor
  4. Confirmar com Biometria

Não é tão fácil como débito, mas dá para pagar dando algum benefício para o vendedor.

Primeiro compre uma TAG adesiva ou um cartão NFC.

Baixe o app NFC Tool: https://play.google.com/store/apps/details?id=com.wakdev.wdnfc

Usando o app do seu banco crie um pagamento PIX com ou sem valor, com identificação se preferir. Copie o PIX "PIX Copia e Cola".

No site https://www.urlencoder.org/pt/ você pode codificar o seu PIX no formato "URL Encoder". Isso vai remover espaços e substituir por "%20" e modificar algum caráter especial se existir.

Agora, no NFC Tool, você vai gravar no cartão uma URL Personalizada. Digite:

pix://localhost?qr=

Cole seu PIX codificado, vai ficar algo assim:

pix://localhost?qr=00020126650014br.gov.bcb.pix01.....B9rp6304E416

Escolha gravar no cartão e pronto.

Proteja seu cartão com senha para nenhum engraçadinho trocar o PIX do seu cartão e direcionar seus pagamentos para ele.

 

FONTE: https://www.bcb.gov.br/content/estabilidadefinanceira/pix/especificacoes_pix_aproximacao_android.pdf

 

quarta-feira, 23 de julho de 2025

FreeRadius bypass

Imaginem se um dia der M... você perdeu seu banco de dados, mas precisa acessar seus equipamentos, precisa liberar o mínimo de acesso aos clientes.

Eu ainda não passei por isso mas a alguns dias o MKSolutions deu uma travada quando eu atualizei um Mikrotik ele registra uma conta com data de 1900 e não remove, eu uso NTP em todos os equipamentos mas algo acontece e sempe que atualizo da verão 6 pra 7 o MKSolutions trava.

Bom isso me deixou muito incomodado e fiquei alguns dias batendo cabeça pra pensar quanto tempo eu levo pra levantar um freeradius genérico.

O modo mais rápido que achei foi baixar um conainer docker

docker run --name radius  -p 1812-1813:1812-1813/udp  -d freeradius/freeradius-server:latest -X

Agora a primeira limitação é que vc precisa saber o secret se seu nas manda o secret.

/etc/freeradius/clients.conf 

client generico {
         ipaddr = 0.0.0.0/0
         proto = *
         secret = testing123 #ajuste esse valor ou nada vai funcionar
         require_message_authenticator = no
         nas_type     = other 
}

Para autenticar os clientes vc tem 4 protocolos configurados mas pense que são 2 formas:

  • PAP onde a senha é enviada em texto claro e vc pode aceitar qualquer senha.
  • CHAP/MSCHAP/MSCHAP2 onde a senha não é enviada e vc ainda precisa retornar uma confirmação que vc sabia qual era a senha. Se todos os seus clientes tiverem usuários diferentes mas a mesma senha também não é um problema.

Para acessar o Mikrotik vc pode querer usar ssh e ai fica fácil nem te pede a senha, ou pode insistir em usar o Winbox que usa CHAP. Vc precisa saber qual é a senha.

Eu criei um modulo python3 vc vai olhar e se souber o minimo vai sacar o que deve mudar nele.

O arquivo radiusd.py fica em /etc/freeradius/mods-config/python3/radiusd.py mas só usei uma constante RLM_MODULE_OK o valor dela é 2 numérico se quiser colocar direto e não usar import.

#! /usr/bin/env python3

import radiusd

def authorize(p):

    reply = (
            ('Mikrotik-Group', 'full'), #libera acesso ao mikrotik
            ('Mikrotik-Address-List', 'radiusList'),
            ('Mikrotik-Rate-Limit', '440m/880m 0k/0k 0k/0k 0/0 8 60m/60m'),
            ('Huawei-Output-Average-Rate', '829440000'),
            ('Huawei-Input-Average-Rate', '409600000'),
            ('Framed-Pool', 'poolRadius'),
            ('Framed-IP-Address', '192.168.100.254'),
            ('Mikrotik-Wireless-PSK', '1234568'),
        )

    config = (
            ('Cleartext-Password', 'senha_padrao'), # necessario para mschap chap
            ('Auth-Type', 'authmod'),
        )

    return (radiusd.RLM_MODULE_OK, reply, config)

def authenticate(p):
    request = dict(p)
    print("*** authenticate ***")
    print(request.get("User-Name", "sem nome"))
    return radiusd.RLM_MODULE_OK

Você vai precisar declarar seu modulo:

/etc/freeradius/mods-enabled/python3
python3 authmod {
    module = authmod
    python_path = /etc/freeradius/python3
    mod_authorize = authmod
    func_authorize = authorize
    mod_authenticate = authmod
    func_authenticate = authenticate
}

E depois de declarar precisa usar então configurar o seu uso no "site".

Aqui temos uma decisão para tomar.

  • Se vc tirar # do que esta no arquivo abaixo vc consegue acesso ao mikrotik por ssh sem colocar senha, mas não vai conseguir acessar por winbox nem autenticar clientes pppoe por chap, só vão logar por PAP no PPPoE.
  • Sem tirar esse comentário qualquer usuário que usar a "senha_padrao" tem acesso. Ou seja não tem muita vantagem.
/etc/freeradius/sites-enabled/default
authorize {
    authmod
}
authenticate {
    # só tire o comentário para acessar por ssh sem senha 
    #Auth-Type mschap {
    #    authmod
    #}
    authmod
}

Espero que seja útil para alguém

Se vc não domina muito bem docker vou deixar alguns comandos que usei muito:

Copiar da sua maquina para o container e executar alguns comando dentro dele:

docker cp mods-available/python3 radius:/etc/freeradius/mods-available/python3
docker exec radius ln -s /etc/freeradius/mods-available/python3 /etc/freeradius/mods-enabled/python3
docker exec radius mkdir /etc/freeradius/python3
docker cp python3/authmod.py radius:/etc/freeradius/python3/authmod.py
docker cp python3/__init__.py radius:/etc/freeradius/python3/__init__.py
docker exec radius cp /etc/freeradius/mods-config/python3/radiusd.py /etc/freeradius/python3/
docker cp sites-available/default radius:/etc/freeradius/sites-available/default

Reiniciar o contaner e olhar o log

docker stop radius
docker start radius
docker logs radius

Exibir arquivos de configuração sem comentários:

docker exec radius grep -vE '^\s*$|^\s*#' /etc/freeradius/clients.conf 

Entrar no shell do container:

docker exec -it radius bash

Testar o login de forma básica

radtest edu 123 localhost 0 testing123

sábado, 19 de julho de 2025

UISP/UNMS não adota M5

Problemas com Nginx Proxy Manager e rádios M5

Eu uso nginx proxy manager e estava tendo problema em conectar meus rádios M5.

Infelizmente a solução reduziu a segurança de todos os meus outros serviços deste proxy porque não achei uma solução que poderia ser aplicada a um único host.

Outro problema: não sei deixar o meu NPM configurado se recriar o container.

Solução: criar certificados na Let's Encrypt do tipo RSA

Para isso eu editei o /etc/letsencrypt.ini alterando key-type = ecdsa para key-type = rsa.

/etc/letsencrypt.ini

text = True
non-interactive = True
webroot-path = /data/letsencrypt-acme-challenge
key-type = rsa
elliptic-curve = secp384r1
preferred-chain = ISRG Root X1

Alteração no algoritmo de troca de chave DH

Para isso precisa criar o arquivo dhparam.pem com o comando:

openssl dhparam -out /etc/nginx/dhparam.pem 2048

Após criar o arquivo precisa ser indicado na configuração com ssl_dhparam, eu escolhi fazer essa configuração em /etc/nginx/conf.d/include/ssl-ciphers.conf

/etc/nginx/conf.d/include/ssl-ciphers.conf
# intermediate configuration. tweak to your needs.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'DHE-RSA-AES128-GCM-SHA256:AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-A
ES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-PO
LY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/dhparam.pem;

Por último precisa reiniciar o nginx.

Configuração no container

Como estou usando container eu copiei e editei localmente os 2 arquivos de configuração depois enviei tudo para o container com os comandos:

docker exec nginx-proxy-manager-app-1 openssl dhparam -out /etc/nginx/dhparam.pem 2048
docker cp letsencrypt.ini nginx-proxy-manager-app-1:/etc/letsencrypt.ini
docker cp ssl-ciphers.conf.bkp nginx-proxy-manager-app-1:/etc/nginx/conf.d/include/ssl-ciphers.conf
docker restart nginx-proxy-manager-app-1

Testando a configuração

Para testar usei o nmap:

nmap --script ssl-enum-ciphers -p 443 uisp.xxxxxx.com.br

sexta-feira, 4 de julho de 2025

Expadir LVM em maquina virtual

Para expandir o disco precisamos:

  1. Com fdisk

    • apagar a partição
    • Recriar a partição com o mesmo setor de inicio

    IMPORTANTE: Não apagar a "LVM2_member signature"

    # fdisk /dev/vdb
    Command (m for help): p
    Disk /dev/vdb: 30 GiB, 32212254720 bytes, 62914560 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x986b9785
    
    Device     Boot Start      End  Sectors Size Id Type
    /dev/vdb1        2048 20971519 20969472  10G 8e Linux LVM
    
    Command (m for help): d 1
    
    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p): p
    Partition number (1-4, default 1):
    First sector (2048-62914559, default 2048):
    Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-62914559, default 62914559):
    
    Created a new partition 1 of type 'Linux' and of size 30 GiB.
    Partition #1 contains a LVM2_member signature.
    
    Do you want to remove the signature? [Y]es/[N]o: n
    
    Command (m for help): w
    
    The partition table has been altered.
    Syncing disks.
  2. Atualizar o PV:

    # pvresize /dev/vdb1
      Physical volume "/dev/vdb1" changed
      1 physical volume(s) resized or updated / 0 physical volume(s) not resized
  3. Expandir a LV:

    # lvextend -l +100%FREE /dev/mediaVG/media
      Size of logical volume mediaVG/media changed from 10.00 GiB (2560 extents) to 30.00 GiB (7680 extents).
      Logical volume mediaVG/media successfully resized.
  4. Expandir o sistema de arquivos ext3/ext4:

    Para sistemas de arquivos ext3 ou ext4, você precisará usar o comando resize2fs para expandir o sistema de arquivos para usar todo o espaço disponível no LV.

    # resize2fs /dev/mediaVG/media
    resize2fs 1.45.5 (07-Jan-2020)
    Filesystem at /dev/mediaVG/media is mounted on /mnt/media; on-line resizing required
    old_desc_blocks = 2, new_desc_blocks = 4
    The filesystem on /dev/mediaVG/media is now 7864320 (4k) blocks long.

    IMPORTANTE: Se o sistema de arquivos estiver montado, o resize2fs fará a expansão online. Se não estiver montado, adicione a opção -f para forçar a verificação do sistema de arquivos antes de expandir.

    Verificando o espaço disponível após a expansão:

    # df -h /mnt/media
    Filesystem               Size  Used Avail Use% Mounted on
    /dev/mapper/mediaVG-media   30G   8G   21G  28% /mnt/media

Dica importante:

Se você estiver usando XFS como sistema de arquivos, o processo é diferente. Para XFS você deve usar:

# xfs_growfs /mnt/media

E o sistema de arquivos deve estar montado durante a operação.

sexta-feira, 27 de junho de 2025

Fedora CoreOS

Para usar o Fedora Core é necessário criar um arquivo de inicialização semelhante à ideia do Cloud-init.

Mas o arquivo de configuração YAML (YAML Ain't Markup Language) é conhecido como Butane.

Esse arquivo precisa ser convertido para JSON, conhecido como Ignition.

Para definir a senha no arquivo, é preciso criar o hash usado no Linux. Uma forma de fazer isso é usando Podman:

podman run -ti --rm quay.io/coreos/mkpasswd --method=yescrypt

Exemplo do arquivo Butane que eu usei:

variant: fcos
version: 1.6.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - ssh-ed25519 AAAAC3NzaXXXXXXXXXXXXXXXII/RsHt5CL/v5juZaj+qmQfw9G+n6J24PzTLu+hIuMOd
      password_hash: $y$j9T$GNBLbCycFxXXXXni1hs.$GHx/wq5SwJpqyXXXXXXXXXXtfDY9nSYqLx7jqpt2w99
storage:
  files:
    - path: /etc/hostname
      mode: 0644
      contents:
        inline: fcos01
    - path: /etc/vconsole.conf
      mode: 0644
      contents:
        inline: |
          KEYMAP=br-abnt2
systemd:
  units:
    - name: "install-qemu-guest-agent.service"
      enabled: true
      contents: |
        [Unit]
        Description=Ensure qemu-guest-agent is installed
        Wants=network-online.target
        After=network-online.target
        Before=zincati.service
        ConditionPathExists=!/var/lib/%N.stamp

        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=rpm-ostree install --allow-inactive --assumeyes --reboot qemu-guest-agent
        ExecStart=/bin/touch /var/lib/%N.stamp

        [Install]
        WantedBy=multi-user.target

Para converter o Butane em Ignition:

No Linux:

podman run -i --rm quay.io/coreos/butane --pretty --strict < fcos.bn | tee fcos.ign

No PowerShell:

Get-Content fcos.bn | 
    podman run -i --rm quay.io/coreos/butane --pretty --strict | 
    ConvertFrom-Json | 
    ConvertTo-Json -Depth 100 -Compress | 
    Set-Content fcos.minimized.ign -Encoding utf8

Ou:

Get-Content fcos.bn | 
    podman run -i --rm quay.io/coreos/butane --pretty --strict | 
    Tee-Object -FilePath fcos2.ign -Encoding utf8

Se for usar VirtualBox:

Depois de importar o arquivo OVA, crie o guestproperty:

"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" guestproperty set 'FCOS' /Ignition/Config "$(cat .\fcos.minimized.ign)"

No meu caso, a máquina chamava FCOS e o arquivo Ignition fcos.minimized.ign.

Se for usar Proxmox, uma opção é iniciar com ISO e depois baixar o ign previamente hospedado por HTTP:

curl -o coreos.ign http://<ip-address>:8080/coreos/coreos.ign
coreos-installer install /dev/sda -i coreos.ign

Outra opção é editar o arquivo:

/etc/pve/qemu-server/<vmid>.conf
args: -fw_cfg name=opt/com.coreos/config,file=path/to/example.ign

Adicione na máquina uma interface serial porque foi configurada como terminal.

quinta-feira, 26 de junho de 2025

PROXMOX - CLOUD-INIT

Como falei antes usar cloud-init e libguestfs é muito útil aqui vou escrever como eu usei.


Primeiro precisa instalar a ferramenta:

apt install libguestfs-tools -y


Eu guardo minhas ISOs em um NFS que não fica no servidor mas está montado nele, então vou trabalhar dele assim posso usar o resultado em todos os servidores da rede, use a pasta onde você guarda suas ISOs e templates.

cd /mnt/pve/nfs-remoto/

Baixe o arquivo da sua distribuição, observe que eu usei genericcloud e extensão raw.

wget https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.raw


Para facilitar minha vida criei um script pra deixar a imagem com os ajustes que eu uso. Mas você pode fazer linha por linha.

Eu criei o arquivo cloud-prep.sh:

#!/bin/bash
IMAGEM="debian-12-genericcloud-amd64.raw"
SERIAL_DEVICE="ttyS0"
BAUD_RATE="115200"

# Instala QEMU Guest Agent
virt-customize -a "$IMAGEM" \
  --install qemu-guest-agent

# Criar diretório de override para serial-getty
virt-customize -a "$IMAGEM" \
  --mkdir /etc/systemd/system/serial-getty@${SERIAL_DEVICE}.service.d

# Criar arquivo de override com autologin root
virt-customize -a "$IMAGEM" \
  --write "/etc/systemd/system/serial-getty@${SERIAL_DEVICE}.service.d/override.conf:[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --keep-baud ${BAUD_RATE},38400,9600 %I \$TERM
TTYVTDisallocate=no"

# Habilitar o serviço serial-getty
virt-customize -a "$IMAGEM" \
  --run-command "systemctl enable serial-getty@${SERIAL_DEVICE}.service"

# Configurar GRUB_CMDLINE_LINUX
virt-customize -a "$IMAGEM" \
  --edit '/etc/default/grub:s/^GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX="console=tty0 console='${SERIAL_DEVICE}','${BAUD_RATE}'"/'

# Configurar GRUB_TERMINAL
virt-customize -a "$IMAGEM" \
  --edit '/etc/default/grub:s/^#?GRUB_TERMINAL=.*/GRUB_TERMINAL="console serial"/'

# Configurar GRUB_SERIAL_COMMAND
virt-customize -a "$IMAGEM" \
  --edit '/etc/default/grub:s/^#?GRUB_SERIAL_COMMAND=.*/GRUB_SERIAL_COMMAND="serial --speed='${BAUD_RATE}' --unit=0 --parity=no --stop=1"/'

# Atualizar configuração do GRUB
virt-customize -a "$IMAGEM" \
  --run-command "update-grub"

echo "Configurado qemu-guest-agent"
echo "Configuração do console serial"

O arquivo deve ser executável:

chmod +x ~/cloud-prep.sh

Execute:

~/cloud-prep.sh

Então use o novo arquivo em suas VMs importando o disco, no exemplo o ID da VM é 101 altere para o de sua VM:

qm importdisk 101 debian-12-genericcloud-amd64.raw local-lvm

Por ultimo adicione ao Hardware da VM o CloudInit Drive para poder fazer as configurações. Eu usei EFI Disk também.