Gerenciador financeiro self-hosted avançado com suporte a importação de extratos (CSV) via Data Importer. Acesso seguro através de túnel do Cloudflare em https://firefly.exemplo.com.
┌─ REDE LOCAL / EXTERNA ────────────────────────────────────┐
│ │
│ Dispositivo ──► https://firefly.exemplo.com │
│ ──► Cloudflare Edge (TLS) ──► Tunnel ──► localhost:8080 │
│ ──► Firefly App (App) ──► Banco de Dados MariaDB (DB) │
│ │
│ Importação de CSV ──► http://IP_DO_SERVIDOR:8081 │
│ ──► Data Importer ──► Firefly App (API) │
└───────────────────────────────────────────────────────────┘
Portas no host:
| Porta Host | Porta Container | Uso |
|---|---|---|
8080/tcp |
8080 |
App Principal (Web UI + API) |
8081/tcp |
8080 |
Data Importer (Conversão e Envio via API) |
Execute todos os comandos no terminal SSH do servidor.
O Firefly precisa persistir o banco de dados e os anexos (uploads).
sudo mkdir -p /srv/firefly/db
sudo mkdir -p /srv/firefly/uploadO container do Firefly App roda internamente usando o usuário www-data (ID 33). Para que o sistema consiga salvar os arquivos e exportações, ele precisa ser o dono da pasta de upload.
sudo chown -R 33:33 /srv/firefly/upload# App principal
sudo ufw allow 8080/tcp
# Data Importer
sudo ufw allow 8081/tcp
sudo ufw reloadO Firefly exige uma chave mestre de criptografia de exatos 32 caracteres. Para gerar uma chave aleatória e segura direto no terminal SSH, rode:
head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32 && echoGuarde o valor gerado. Você vai precisar dele no próximo passo.
- Acessar o Portainer → Stacks → Add Stack
- Nome:
firefly - Colar o conteúdo do arquivo
assets/stacks/firefly.ymlno Editor Web. - Na aba Environment variables, adicione manualmente (Add environment variable) ou carregue do seu
.envas seguintes chaves:FIREFLY_APP_KEY: Cole aqui a chave de 32 caracteres gerada no passo anterior.FIREFLY_DB_PASSWORD: Senha para o banco de dados.FIREFLY_APP_TOKEN: Pode deixar vazio no deploy inicial.
- Clicar em Deploy the stack.
Warning
O Firefly é muito sensível a proxies reversos e proteções HTTP. Faça a configuração abaixo no painel do Cloudflare para evitar falhas graves na interface, como o mascaramento do seu login.
No painel do Cloudflare:
- Vá em Scrape Shield → Email Address Obfuscation e desative (Off). O Cloudflare ofusca emails como proteção anti-bot, o que quebra a interface do Firefly, substituindo seu email por
[email protected].
Note
A variável TRUSTED_PROXIES=** já está definida na sua stack assets/stacks/firefly.yml. Ela é obrigatória para resolver o erro "Could not delete" (falha de CSRF no Laravel ao usar túneis).
O firefly-importer acessa a API do app principal para realizar a inserção de dados em massa. Ele precisa de um Personal Access Token.
- Acesse o Firefly (
http://192.168.x.x:8080ou via Domínio) e crie sua conta admin. - Menu lateral → Opções → Perfil.
- Aba OAuth → Seção Personal Access Tokens.
- Clique em Criar Novo Token, nomeie como
Importere copie o código gigante. - Volte no Portainer → Stack
firefly→ Editor. - Insira o token copiado no valor da variável
FIREFLY_APP_TOKEN. - Clique em Update the stack.
A migração utiliza o Data Importer, acessível apenas localmente.
Important
A maioria dos apps financeiros, como o Mobills, exporta relatórios CSV em formato UTF-16 LE. O Firefly Data Importer exige UTF-8 e falhará miseravelmente se a conversão não for feita.
No Windows (PowerShell), rode o comando abaixo na pasta do relatório original para convertê-lo com segurança:
Get-Content "RELATORIO_TRANSACOES.csv" -Encoding Unicode | Set-Content "RELATORIO_UTF8.csv" -Encoding UTF8O Data Importer não cria contas automaticamente. Abra o CSV, verifique as contas financeiras presentes (ex: Nubank, Carteira, Sicoob) e crie cada uma manualmente no Firefly em Contas → Contas de Ativo (Asset accounts).
Se o arquivo exportado passar de ~2.000 linhas, a interface web do importador sofrerá Timeout (504). A solução recomendada pela documentação oficial é fatiar o arquivo, mas mantendo a linha do cabeçalho em todas as partes.
Script PowerShell para automatizar a divisão (RELATORIO_UTF8.csv):
$source = "RELATORIO_UTF8.csv"
$destDir = "split"
New-Item -ItemType Directory -Force -Path $destDir | Out-Null
$reader = New-Object System.IO.StreamReader($source, [System.Text.Encoding]::UTF8)
$header = $reader.ReadLine()
$chunkSize = 2000
$fileCount = 1
$lineCount = 0
$writer = $null
while ($null -ne ($line = $reader.ReadLine())) {
if ($lineCount % $chunkSize -eq 0) {
if ($null -ne $writer) { $writer.Close() }
$destFile = Join-Path $destDir "RELATORIO_UTF8_part$fileCount.csv"
$writer = New-Object System.IO.StreamWriter($destFile, $false, [System.Text.Encoding]::UTF8)
$writer.WriteLine($header)
$fileCount++
}
$writer.WriteLine($line)
$lineCount++
}
if ($null -ne $writer) { $writer.Close() }
$reader.Close()- Acesse o importador:
http://192.168.x.x:8081 - Suba o primeiro lote (
part1.csv) e faça o mapeamento visual das colunas (Data, Valor, Conta) e a ligação dos papéis (Account Mapping). - Na penúltima tela, antes do envio para a API, baixe o arquivo de configuração (.json) disponibilizado.
- Processe a
part1.csv. - Volte para o início (Start Over). Faça upload da
part2.csvjunto com o arquivo .json baixado. - Na seção inferior, marque a opção Skip form: Yes e confirme. O sistema usará o mapeamento prévio e enviará diretamente para a nuvem. Repita para as demais partes.
Log exibe:
Line #384: [a117]: transactions.0.amount: O valor precisa ser maior do que zero. (original value: "0.00")
Causa: O Mobills e outros apps aceitam transações zeradas (como rascunhos, estornos ou marcações). O Firefly exige que toda transação tenha um valor financeiro real. Fix: Nenhuma ação necessária. O importador ignora a linha infratora com segurança e prossegue com sucesso para o restante do lote.
Causa: O mecanismo CSRF do Laravel está rejeitando pacotes HTTP por considerar a origem não-confiável.
Fix: Certifique-se de que a variável TRUSTED_PROXIES=** está presente no Portainer na stack do firefly-app e recarregue o container.
Causa: Ocorre após a tela de erro 504 no Data Importer. O tempo de execução excedeu o limite do PHP/Nginx e o container web perdeu o contexto temporário do processamento em andamento. Fix: Aplique a solução descrita na etapa 4.3. Dividindo CSV Gigante.
| Recurso | URL |
|---|---|
| Web UI (App) | https://firefly.exemplo.com |
| Local (App) | http://IP_DO_SERVIDOR:8080 |
| Data Importer | http://IP_DO_SERVIDOR:8081 |
| Portainer | Stack firefly |