Moon Flower Society > Plano de implantação da Webtilde runv.club com copyparty
Arquitetura, instalação, segurança, operação e evolução de uma comunidade de páginas pessoais inspirada nas tildes, mas administrada pela web com copyparty.
Posted July 13, 2026. Markdown. Tags: tilde, copyparty, debian, docker, small-web, comunidade, runv.
Este documento descreve um experimento comunitário inspirado em tilde, pubnix, small web e hospedagem pessoal clássica, mas com uma diferença deliberada: no primeiro estágio, os membros não recebem uma conta Unix nem acesso SSH. Cada participante recebe uma área própria para publicar um pequeno site estático e administra os arquivos pelo navegador, WebDAV ou ferramentas compatíveis com o copyparty.
O resultado não deve ser vendido como uma pubnix completa. O nome tecnicamente honesto é webtilde: uma comunidade de páginas pessoais com identidade, diretório de membros, páginas atualizadas recentemente, webring, regras comuns e sensação de vizinhança digital.
A proposta não é criar “mais uma hospedagem grátis”. É criar um lugar pequeno, reconhecível e humano, no qual cada membro possua um canto da web e consiga publicá-lo sem depender de Git, terminal ou plataforma comercial.
A implementação recomendada usa duas instâncias independentes do copyparty:
party.runv.club.pages.runv.club.Ambas enxergam os mesmos diretórios dos membros, porém com permissões diferentes:
h, que entrega index.html e não exibe a listagem normal de diretórios;Essa separação é a decisão mais importante de todo o projeto. Executar a interface administrativa e o HTML arbitrário dos membros no mesmo domínio seria uma economia burra: reduz containers, mas aumenta desnecessariamente a superfície de ataque.
A Webtilde oferecerá:
pages.runv.club/~usuario/;Na primeira versão, ele não fornecerá:
cron individual;Isso significa que a Webtilde será uma experiência de publicação comunitária, não uma máquina Unix compartilhada. Uma fase futura poderá conectar a mesma comunidade a contas Debian reais, sem jogar fora a camada web criada agora.
O usuário deve conseguir publicar o primeiro site em poucos minutos, sem conhecer Linux. O onboarding começa com um index.html funcional, uma folha de estilo simples e instruções curtas.
Os sites permanecem em diretórios comuns do sistema. Não existe importação para armazenamento proprietário nem banco obrigatório para guardar o conteúdo.
A interface de edição nunca deve compartilhar domínio, cookies ou permissões com as páginas públicas.
O container público recebe os arquivos como somente leitura. O container editor roda com usuário sem privilégios e só escreve na árvore destinada aos membros.
Diretório, páginas recentes, webring, regras claras e projetos coletivos são mais importantes do que adicionar cinquenta protocolos.
A primeira versão deve ser pequena, reversível e observável. Recursos perigosos — principalmente JavaScript de usuários e contas Unix reais — entram apenas depois que o modelo básico estiver estável.
INTERNET
│
▼
Nginx / Caddy / Pangolin
TLS + limites + logs
│ │
party.runv.club pages.runv.club
│ │
▼ ▼
copyparty-editor copyparty-pages
autenticado público
leitura/escrita somente leitura
│ │
└────────┬────────┘
▼
/srv/webtilde/users/
├── alice/public_html/
├── bruno/public_html/
└── pablo/public_html/
│
▼
gerador do portal comunitário
membros + recentes + RSS + webring
| Componente | Responsabilidade | Exposição |
|---|---|---|
| Debian 13 | Sistema-base, armazenamento e serviços | Administração restrita |
| Docker Engine + Compose | Isolamento e atualização das instâncias | Não exposto diretamente |
copyparty-editor |
Login, upload, renomeação e edição | party.runv.club |
copyparty-pages |
Servir os sites estáticos | pages.runv.club |
| Proxy reverso | HTTPS, domínios, IP real, limites e cabeçalhos | Portas 80/443 |
| Registro de membros | Fonte de verdade de usuários e estado | Somente administrador |
| Gerador do portal | Diretório, recentes, página aleatória e RSS | Publicado como site estático |
| Restic ou Borg | Backup versionado e restauração | Destino externo |
| Prometheus ou logs | Visibilidade operacional | Restrito |
| Função | Endereço sugerido |
|---|---|
| Portal comunitário | tilde.runv.club ou runv.club |
| Editor e arquivos | party.runv.club |
| Sites dos membros | pages.runv.club/~usuario/ |
| Documentação | help.runv.club ou uma seção do portal |
| Estado do serviço | status.runv.club |
Os nomes são propostas. A exigência arquitetural é manter o editor e os sites publicados em origens diferentes.
/opt/webtilde/
├── compose.yaml
├── .env
├── config/
│ ├── editor/
│ │ ├── copyparty.conf
│ │ └── generated/
│ │ ├── accounts.conf
│ │ └── volumes.conf
│ └── pages/
│ ├── copyparty.conf
│ └── generated/
│ └── volumes.conf
├── state/
│ ├── editor/
│ └── pages/
├── registry/
│ └── members.tsv
├── scripts/
│ ├── add-member.sh
│ ├── suspend-member.sh
│ ├── remove-member.sh
│ ├── render-config.py
│ ├── build-community.py
│ ├── validate-sites.sh
│ └── backup.sh
├── templates/
│ └── starter-site/
└── backups/
/srv/webtilde/users/
├── alice/
│ └── public_html/
│ ├── index.html
│ ├── style.css
│ └── assets/
├── bruno/
│ └── public_html/
└── pablo/
└── public_html/
O diretório /srv/webtilde/users contém conteúdo dos membros. /opt/webtilde contém infraestrutura, configuração e automação. Misturar ambos torna backup, permissões e restauração mais confusos.
O projeto deve manter um registro simples e legível, inicialmente em TSV:
username display_name email status created_at quota_mb
alice Alice alice@example.invalid active 2026-07-13 100
bruno Bruno bruno@example.invalid active 2026-07-13 100
Esse arquivo não é servido publicamente. O e-mail pode ser omitido do portal comunitário e deve existir apenas para administração.
Formato recomendado:
^[a-z][a-z0-9_-]{1,30}$
Regras adicionais:
Nomes reservados mínimos:
admin
api
assets
help
login
logout
members
new
random
recent
root
rss
static
status
support
www
As senhas não devem aparecer em texto puro nos arquivos versionados. O copyparty oferece hashing de senhas; o plano usa Argon2 quando disponível na imagem instalada.
Fluxo recomendado:
Nunca coloque a senha real em exemplos, tickets, logs ou repositório Git.
Cada usuário recebe:
https://pages.runv.club/~alice/
O caminho físico correspondente é:
/srv/webtilde/users/alice/public_html/
No momento da criação da conta, o sistema copia um site inicial:
public_html/
├── index.html
├── style.css
├── README.txt
└── assets/
O index.html inicial deve ser curto, editável e sem framework. Um modelo excessivamente sofisticado ensina o usuário a ter medo de mexer nele.
.html;.css;.txt;.md como arquivo para download, não como aplicação;.env;O bloqueio deve existir em três camadas: regras comunitárias, validação automatizada e configuração do proxy. Nenhuma camada isolada é suficiente.
Uma única instância seria capaz de editar e servir os arquivos, mas criaria um problema conceitual: o domínio autenticado teria contato direto com HTML e SVG controlados pelos membros.
O desenho recomendado evita isso:
party.runv.club
└── interface autenticada
└── HTML do usuário tratado como arquivo/texto, não como página confiável
pages.runv.club
└── conteúdo público
└── container sem escrita e sem credenciais administrativas
Durante o piloto, JavaScript de membros deve permanecer desabilitado por CSP e pelo noscript do copyparty.
Razões:
pages.runv.club;HTML e CSS já permitem páginas pessoais excelentes. JavaScript entra apenas quando houver isolamento por subdomínio, por exemplo:
alice.pages.runv.club
bruno.pages.runv.club
No editor, aplique nohtml aos volumes dos membros. Isso faz HTML e SVG serem tratados de forma conservadora e também reduz riscos ligados à renderização de Markdown.
Além disso:
Sites de usuários não devem poder escapar da própria árvore por symlink.
Medidas:
/, /etc, /home ou socket Docker dentro dos containers.Montar /var/run/docker.sock seria uma falha crítica. Não existe justificativa para isso neste projeto.
Para o piloto:
| Limite | Valor inicial | Justificativa |
|---|---|---|
| Espaço por membro | 100 MiB | Suficiente para HTML, CSS e imagens otimizadas |
| Quantidade de arquivos | 2.000 | Evita milhões de arquivos pequenos |
| Tamanho por arquivo | 25 MiB | Impede uso como depósito de vídeo e backup |
| Espaço livre mínimo global | 5 GiB | Evita preencher completamente o filesystem |
| Membros do piloto | 5 a 10 | Permite observar abuso e ergonomia |
| Duração da fase fechada | 30 dias | Tempo suficiente para testar operação real |
O copyparty oferece flags como sz, df, vmaxb e vmaxn. Os limites totais por volume dependem de indexação, por isso o volume do editor deve usar e2ds.
A quota deve ser revisada com dados reais. Começar com 1 GiB por pessoa seria generoso, mas operacionalmente preguiçoso: incentiva transformar a comunidade em file host antes de provar o conceito.
sudo ou sessão root consciente.sudo useradd \
--system \
--home-dir /srv/webtilde \
--create-home \
--shell /usr/sbin/nologin \
webtilde
sudo install -d -o webtilde -g webtilde -m 0750 \
/srv/webtilde/users
sudo install -d -o root -g webtilde -m 0750 \
/opt/webtilde \
/opt/webtilde/config/editor/generated \
/opt/webtilde/config/pages/generated \
/opt/webtilde/registry \
/opt/webtilde/scripts \
/opt/webtilde/templates/starter-site \
/opt/webtilde/backups
sudo install -d -o webtilde -g webtilde -m 0750 \
/opt/webtilde/state/editor \
/opt/webtilde/state/pages
WT_UID="$(id -u webtilde)"
WT_GID="$(id -g webtilde)"
sudo tee /opt/webtilde/.env >/dev/null <<EOF_ENV
WT_UID=${WT_UID}
WT_GID=${WT_GID}
TZ=America/Sao_Paulo
EOF_ENV
sudo chmod 0640 /opt/webtilde/.env
sudo chown root:webtilde /opt/webtilde/.env
A versão abaixo é fixada em 1.20.18 para tornar a implantação reproduzível. Antes da instalação real, confira a versão estável atual e os avisos de segurança; não troque silenciosamente por latest.
services:
editor:
image: copyparty/ac:1.20.18
container_name: webtilde-editor
restart: unless-stopped
init: true
user: "${WT_UID}:${WT_GID}"
ports:
- "127.0.0.1:3923:3923"
volumes:
- ./config/editor:/cfg:ro
- ./state/editor:/state:rw
- /srv/webtilde/users:/w/users:rw
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=256m
environment:
TZ: ${TZ}
pages:
image: copyparty/ac:1.20.18
container_name: webtilde-pages
restart: unless-stopped
init: true
user: "${WT_UID}:${WT_GID}"
ports:
- "127.0.0.1:3924:3923"
volumes:
- ./config/pages:/cfg:ro
- ./state/pages:/state:rw
- /srv/webtilde/users:/w/users:ro
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=256m
environment:
TZ: ${TZ}
Salve como:
/opt/webtilde/compose.yaml
Arquivo:
/opt/webtilde/config/editor/copyparty.conf
Conteúdo proposto:
[global]
p: 3923
name: runv Webtilde Editor
hist: /state/hists
no-robots
no-logues
no-readme
ah-alg: argon2
chpw
chpw-db: /state/chpw.json
rproxy: 1
xff-hdr: x-forwarded-for
% /cfg/generated
Observações:
allow-csrf.Arquivo:
/opt/webtilde/config/pages/copyparty.conf
Conteúdo proposto:
[global]
p: 3923
name: runv Webtilde Pages
hist: /state/hists
no-logues
no-readme
rproxy: 1
xff-hdr: x-forwarded-for
% /cfg/generated
O publicador não precisa conter contas dos membros. Sua função é exclusivamente servir os volumes aprovados.
Arquivo:
/opt/webtilde/config/editor/generated/accounts.conf
[accounts]
admin: <HASH_ARGON2_DO_ADMINISTRADOR>
alice: <HASH_ARGON2_DA_ALICE>
Arquivo:
/opt/webtilde/config/editor/generated/volumes.conf
[/u/alice/site]
/w/users/alice/public_html
accs:
rwmd: alice
A: admin
flags:
e2ds
nohtml
sz: 1b-25m
df: 5g
vmaxb: 100m
vmaxn: 2k
Interpretação:
alice pode ler, escrever, mover e apagar dentro do próprio site;admin possui acesso administrativo;nohtml protege a interface de edição contra renderização ativa do conteúdo;e2ds mantém o índice necessário para quotas totais;Arquivo:
/opt/webtilde/config/pages/generated/volumes.conf
[/~alice]
/w/users/alice/public_html
accs:
h: *
flags:
noscript
A permissão h faz o volume agir como hospedagem web tradicional: entrega index.html e não oferece a listagem normal da pasta.
O bind mount :ro no Compose é tão importante quanto a permissão interna. Mesmo que uma configuração futura seja escrita incorretamente, o container público ainda não deve conseguir alterar os arquivos.
cd /opt/webtilde
sudo docker compose config
sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=100 editor
sudo docker compose logs --tail=100 pages
curl -I http://127.0.0.1:3923/
curl -I http://127.0.0.1:3924/~alice/
Não publique os domínios antes de confirmar:
O proxy deve:
Host correto;server {
listen 443 ssl http2;
server_name party.runv.club;
client_max_body_size 32m;
location / {
proxy_pass http://127.0.0.1:3923;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
server {
listen 443 ssl http2;
server_name pages.runv.club;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'none'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'" always;
location ~* /(?:\.git|\.svn|\.hg)(?:/|$) {
return 404;
}
location ~* \.(?:env|ini|log|sql|bak|swp|tmp)$ {
return 404;
}
location / {
proxy_pass http://127.0.0.1:3924;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 300s;
}
}
A configuração de certificado depende do proxy já usado na infraestrutura. Não copie uma configuração TLS genérica por cima de um ambiente que já usa Pangolin, Traefik, Caddy ou CloudPanel.
add-memberO processo de criação deve ser idempotente e executar, nesta ordem:
Depois de alterar apenas contas ou volumes:
sudo docker kill --signal=USR1 webtilde-editor
sudo docker kill --signal=USR1 webtilde-pages
Mudanças globais exigem recriação ou reinício controlado:
cd /opt/webtilde
sudo docker compose up -d --force-recreate editor pages
Suspender não significa apagar imediatamente.
O script deve:
status=suspended no registro;A remoção definitiva deve exigir uma segunda ação administrativa e um backup anterior.
Fluxo recomendado:
active → suspended → archived → deleted
Não implemente um botão que apaga árvore de usuário diretamente a partir de uma requisição web. Isso seria uma forma desnecessariamente elegante de perder dados.
O copyparty cuida dos arquivos, mas não cria sozinho a cultura da comunidade. Um pequeno gerador estático deve construir o portal.
/
/about/
/join/
/rules/
/help/
/members/
/recent/
/random/
/projects/
webring/
feed.xml
Cada entrada pode exibir:
~username;Não exiba e-mail, IP, quota, nome civil obrigatório ou estatísticas invasivas.
O gerador pode usar a data de modificação dos arquivos ou, preferencialmente, um estado próprio atualizado pelo hook de publicação.
Regras úteis:
O botão “visitar uma página aleatória” é pequeno, mas essencial. Ele faz a comunidade parecer um lugar navegável, não uma tabela de contas.
Cada site inicial recebe links “anterior”, “aleatório” e “próximo”. O gerador recalcula a ordem a partir dos membros ativos.
O feed deve publicar somente eventos de atualização, por exemplo:
Alice atualizou sua página pessoal.
Bruno publicou um novo projeto.
Pablo alterou a seção de leituras.
Não copie o conteúdo integral dos sites sem consentimento.
O membro recebe:
Seu site: https://pages.runv.club/~alice/
Editor: https://party.runv.club/u/alice/site/
Ajuda: https://help.runv.club/
O tutorial inicial deve pedir apenas:
index.html;style.css;login no editor
→ editar ou enviar arquivos
→ salvar
→ página pública muda imediatamente
→ gerador comunitário registra atualização
Não é necessário um processo separado de “deploy” no MVP. A pasta editada é a mesma pasta que o publicador lê, com permissões de montagem diferentes.
Depois que a interface web estiver estável, usuários podem conectar via WebDAV ao editor. Isso permite uso por gerenciadores de arquivos e editores locais.
Não habilite simultaneamente FTP, SFTP, SMB e TFTP só porque o software oferece. Cada protocolo adicional aumenta documentação, suporte e superfície de ataque. Web e WebDAV cobrem o experimento inicial.
A política precisa ser curta o bastante para ser lida e clara o bastante para ser aplicada.
Deixe explícito:
Logs sem revisão são decoração técnica. Defina retenção e alertas desde o piloto.
/srv/webtilde/users/
/opt/webtilde/config/
/opt/webtilde/registry/
/opt/webtilde/scripts/
/opt/webtilde/templates/
/opt/webtilde/compose.yaml
/opt/webtilde/.env
O estado de índices do copyparty pode ser reconstruído, mas salvá-lo pode acelerar recuperação. Credenciais e arquivos de ambiente exigem criptografia no destino.
| Camada | Frequência | Retenção |
|---|---|---|
| Snapshot local | A cada 6 horas | 7 dias |
| Backup externo incremental | Diário | 30 dias |
| Backup mensal | Mensal | 12 meses |
| Teste de restauração | Mensal | Relatório obrigatório |
Uma restauração válida não é “o comando terminou sem erro”. Ela deve comprovar:
cd /opt/webtilde
sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=100 editor pages
Esse comando só deve ser executado depois de alterar conscientemente a tag da imagem no Compose. pull não é política de atualização; é apenas transporte.
A versão 1.20.18, publicada em julho de 2026, aparece neste documento como referência pesquisada. O projeto havia corrigido uma vulnerabilidade relevante na versão anterior, o que reforça a necessidade de acompanhar advisories e não abandonar o serviço em uma tag antiga.
index.html é entregue na raiz do usuário;index.html falha de maneira previsível;/etc do host;webtilde;Duração sugerida: 1 a 3 dias.
Objetivos:
nohtml, noscript e h validados;Critério de saída: arquitetura comprovada sem domínio público.
Duração sugerida: 30 dias.
Escopo:
Critérios de sucesso:
Escopo:
Critério de saída: processo sustentável sem depender de improviso diário do administrador.
Modelo:
alice.pages.runv.club
bruno.pages.runv.club
Benefícios:
Custos:
JavaScript só deve ser considerado depois dessa fase.
A comunidade pode ganhar contas Debian e SSH mantendo o copyparty como interface opcional.
/home/alice/public_html
▲ ▲
│ │
SSH copyparty
Essa fase adiciona:
Não tente implementar isso no mesmo dia da Webtilde. São produtos operacionalmente diferentes.
| Risco | Impacto | Resposta |
|---|---|---|
| XSS no editor | Roubo de sessão administrativa | Origem separada + nohtml + sem upload anônimo |
| Script de um membro atinge outro | Interferência entre sites | JavaScript bloqueado até subdomínios isolados |
| Disco cheio | Queda do serviço e corrupção | Quotas + df + alertas + filesystem separado |
| Configuração manual inconsistente | Acesso cruzado | Registro único + gerador idempotente + testes |
| Apagar usuário por engano | Perda de conteúdo | Suspensão antes de remoção + backup |
| Symlink escapando da pasta | Exposição do host | Bind mounts mínimos + varredura + container sem privilégios |
| Versão vulnerável | Comprometimento remoto | Tags fixas + advisories + atualização testada |
| Projeto vira depósito de arquivos | Custo e abuso | 100 MiB + 25 MiB por arquivo + regras claras |
| Administrador vira gargalo | Projeto abandona usuários | Scripts, documentação, métricas e onboarding previsível |
| Confusão com pubnix completa | Expectativa errada | Chamar de Webtilde e explicar limites desde o início |
latest sem revisão;A última armadilha é especialmente comum: transformar um experimento simples de páginas pessoais em uma plataforma SaaS caseira antes de existir uma comunidade. O software passa a consumir toda a energia e a parte humana nunca nasce.
Não use pageviews como única métrica. Uma webtilde com vinte páginas cuidadas e vínculos reais é mais bem-sucedida do que uma hospedagem com mil contas abandonadas.
webtilde sem shellnohtml no editornoscript no publicadorh nos sitesO copyparty possui integração com provedores de identidade e mecanismos de volumes dinâmicos. Isso pode reduzir configuração repetida, mas também aumenta o número de estados implícitos e torna o comportamento de reinicialização e herança de permissões mais difícil de auditar.
Para um piloto com até dez pessoas, gerar explicitamente contas e volumes é menos elegante e muito mais verificável. Depois que o modelo de permissões estiver provado, um IdP pode ser introduzido com testes específicos.
Volumes separam caminhos e permissões, mas não criam o mesmo grau de isolamento operacional de processos diferentes. Com duas instâncias:
O custo é um pouco mais de RAM e dois serviços para acompanhar. Neste caso, a clareza de segurança vale mais do que a economia marginal.
Somente quando cada membro tiver uma origem independente, idealmente um subdomínio próprio, e depois de validar:
Mesmo com subdomínios, JavaScript continua sendo conteúdo ativo de terceiros. A diferença é que o navegador oferece uma fronteira de origem muito mais útil.
cd /opt/webtilde
sudo docker compose down
Esse comando remove os containers e a rede do Compose, mas não deve apagar:
/srv/webtilde/users/
/opt/webtilde/config/
/opt/webtilde/state/
/opt/webtilde/registry/
Antes de qualquer remoção definitiva:
sudo tar -C / -czf /root/webtilde-pre-remove.tar.gz \
opt/webtilde \
srv/webtilde
Esse arquivo local não substitui backup externo. Ele apenas reduz a chance de uma desinstalação apressada virar perda imediata.
A pesquisa para este plano foi baseada principalmente em fontes primárias:
9001/copyparty;Pontos incorporados diretamente ao desenho:
h para comportamento de servidor web;nohtml e noscript para conteúdo não confiável;sz, df, vmaxb e vmaxn;e2ds para limites totais do volume;USR1;copyparty/ac;/cfg para configurações e /w para conteúdo;Os blocos de configuração são um projeto técnico detalhado e coerente com a documentação pesquisada, mas devem passar por validação em uma máquina de testes antes da abertura pública. Versões futuras podem alterar flags, comportamento de cabeçalhos ou formato de configuração.
public_html poderá futuramente ser acessada por SSH em uma tilde Debian real.O melhor primeiro resultado não é uma infraestrutura impressionante. É abrir pages.runv.club/~alguem/ e encontrar uma página estranha, pessoal e claramente feita por uma pessoa.
View the original Markdown file
Ideas | What changed | RSS | About | Text version
Pablo Murad <pablomurad@pm.me>