--- # ─── Front-matter ───────────────────────────────────────────────────── # Este documento segue o mesmo molde estrutural do example.md: # título, data, resumo, tags, cor, seções, tabelas, código e detalhes. title: Plano de implantação da Webtilde runv.club com copyparty date: 2026-07-13 summary: 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. tags: [tilde, copyparty, debian, docker, small-web, comunidade, runv] flowerColor: "#c7d2fe" --- # Plano da Webtilde runv.club com copyparty 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. ## Resumo executivo A implementação recomendada usa **duas instâncias independentes do copyparty**: 1. **Editor autenticado** em `party.runv.club`. 2. **Servidor público somente leitura** em `pages.runv.club`. Ambas enxergam os mesmos diretórios dos membros, porém com permissões diferentes: - o editor monta os arquivos com leitura e escrita; - o publicador monta os mesmos arquivos como somente leitura; - HTML enviado por usuários não é executado dentro da origem autenticada; - os sites públicos são servidos com a permissão `h`, que entrega `index.html` e não exibe a listagem normal de diretórios; - JavaScript permanece desabilitado durante o piloto; - o proxy reverso é o único componente exposto à internet. 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. ## O que este experimento será A Webtilde oferecerá: - uma página pessoal por membro; - endereço público no formato `pages.runv.club/~usuario/`; - edição e upload por navegador; - possibilidade de WebDAV para usuários mais técnicos; - HTML e CSS artesanais; - imagens, fontes, áudio curto e pequenos arquivos estáticos; - uma página inicial comunitária; - diretório de membros; - páginas recentemente atualizadas; - botão de página aleatória; - webring interno; - feed RSS coletivo de atualizações; - regras, documentação e modelos iniciais; - quotas previsíveis por membro; - aprovação manual de inscrições no piloto; - backup e restauração testados. ## O que este experimento não será Na primeira versão, ele não fornecerá: - shell Unix; - SSH interativo; - processos persistentes; - `cron` individual; - execução de PHP, Python, Node.js ou CGI; - banco de dados por usuário; - portas de rede particulares; - containers individuais; - e-mail Unix; - compiladores no servidor; - Git executado no servidor; - sincronização bidirecional estilo Dropbox; - construtor visual de sites; - WordPress ou qualquer CMS dinâmico. 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. ## Princípios do projeto ### Simplicidade visível 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. ### Estrutura de arquivos normal 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. ### Separação entre edição e publicação A interface de edição nunca deve compartilhar domínio, cookies ou permissões com as páginas públicas. ### Poucos privilégios 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. ### Comunidade antes de recursos Diretório, páginas recentes, webring, regras claras e projetos coletivos são mais importantes do que adicionar cinquenta protocolos. ### Evolução por fases 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. --- ## Arquitetura proposta ```text 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 ``` ## Componentes | 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 | ## Domínios sugeridos | 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. ## Estrutura de armazenamento ```text /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. --- ## Modelo de identidade ### Fonte de verdade O projeto deve manter um registro simples e legível, inicialmente em TSV: ```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. ### Regras de nome de usuário Formato recomendado: ```regex ^[a-z][a-z0-9_-]{1,30}$ ``` Regras adicionais: - sempre minúsculo; - entre 2 e 31 caracteres; - sem ponto; - sem espaço; - sem acento; - não permitir nomes reservados; - não permitir nomes visualmente enganosos; - nome não é reciclado imediatamente após remoção. Nomes reservados mínimos: ```text admin api assets help login logout members new random recent root rss static status support www ``` ### Senhas 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: 1. gerar uma senha inicial aleatória; 2. gerar o hash usando a própria versão do copyparty em produção; 3. gravar apenas o hash na configuração; 4. entregar a senha por canal separado; 5. permitir troca pelo usuário; 6. invalidar a credencial no momento da suspensão. Nunca coloque a senha real em exemplos, tickets, logs ou repositório Git. --- ## Modelo de publicação ### Endereço público Cada usuário recebe: ```text https://pages.runv.club/~alice/ ``` O caminho físico correspondente é: ```text /srv/webtilde/users/alice/public_html/ ``` ### Arquivo inicial No momento da criação da conta, o sistema copia um site inicial: ```text 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. ### Tipos de conteúdo permitidos no piloto - `.html`; - `.css`; - imagens web comuns; - `.txt`; - `.md` como arquivo para download, não como aplicação; - fontes locais em formatos web; - pequenos áudios, desde que respeitem a quota; - favicon e manifesto estático. ### Conteúdo bloqueado ou não suportado - executáveis; - scripts de servidor; - PHP; - CGI; - binários grandes; - arquivos de banco de dados; - backups privados; - dumps SQL; - chaves, tokens e arquivos `.env`; - conteúdo ilegal ou abusivo; - páginas que tentem imitar o login da própria comunidade. O bloqueio deve existir em três camadas: regras comunitárias, validação automatizada e configuração do proxy. Nenhuma camada isolada é suficiente. --- ## Segurança da origem web ### Por que não usar uma única instância 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: ```text 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 ``` ### Política de JavaScript Durante o piloto, JavaScript de membros deve permanecer desabilitado por CSP e pelo `noscript` do copyparty. Razões: - todos os membros usam inicialmente a mesma origem `pages.runv.club`; - JavaScript de um membro poderia tentar interagir com conteúdo de outro membro na mesma origem; - cookies e armazenamento local também pertencem à origem, não ao caminho; - permitir scripts agora cria complexidade sem melhorar a essência do experimento. HTML e CSS já permitem páginas pessoais excelentes. JavaScript entra apenas quando houver isolamento por subdomínio, por exemplo: ```text alice.pages.runv.club bruno.pages.runv.club ``` ### Conteúdo na interface de edição 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: - desative prologues e epilogues; - desative renderização automática de README na interface; - não permita arquivos ocultos por padrão; - não ofereça upload anônimo; - não exponha FTP, TFTP, SMB ou SFTP durante o piloto; - mantenha apenas HTTP interno atrás do proxy HTTPS. ### Links simbólicos Sites de usuários não devem poder escapar da própria árvore por symlink. Medidas: - container com bind mount limitado; - volume público montado como somente leitura; - validação periódica de symlinks; - rejeição de links que apontem para fora da pasta; - nenhuma montagem de `/`, `/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. --- ## Quotas iniciais 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. --- ## Instalação no Debian ### Pré-requisitos - Debian 13 atualizado; - domínio sob seu controle; - proxy reverso funcional; - Docker Engine instalado pelo repositório oficial; - plugin Docker Compose; - backup externo disponível; - firewall permitindo publicamente apenas 80/443 e a porta SSH administrativa; - usuário administrador com `sudo` ou sessão root consciente. ### 1. Criar usuário e diretórios ```bash 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 < alice: ``` Arquivo: ```text /opt/webtilde/config/editor/generated/volumes.conf ``` ```ini [/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; - a quota é aplicada no volume daquele membro. ### 6. Exemplo de configuração gerada do publicador Arquivo: ```text /opt/webtilde/config/pages/generated/volumes.conf ``` ```ini [/~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. ### 7. Validar configuração e iniciar ```bash 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: - containers estáveis; - ausência de erro de permissão; - login funcionando no editor; - usuário sem acesso ao volume de outro membro; - site público funcionando sem autenticação; - tentativa de escrita no container público falhando; - HTML no editor não executando; - JavaScript do site público bloqueado durante o piloto. --- ## Proxy reverso ### Regras essenciais O proxy deve: - terminar TLS; - enviar `Host` correto; - enviar IP real do cliente; - enviar protocolo original; - desativar buffering de upload quando necessário; - aceitar uploads maiores que o padrão do Nginx; - usar timeouts suficientes para conexões lentas; - não expor diretamente as portas 3923 e 3924; - manter editor e páginas em virtual hosts distintos. ### Exemplo para o editor ```nginx 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; } } ``` ### Exemplo para as páginas públicas ```nginx 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. --- ## Automação de membros ### Script `add-member` O processo de criação deve ser idempotente e executar, nesta ordem: 1. validar o nome de usuário; 2. verificar nomes reservados; 3. confirmar que o usuário não existe; 4. criar diretório temporário; 5. copiar o site inicial; 6. aplicar proprietário e modo corretos; 7. adicionar o membro ao registro; 8. gerar hash da senha; 9. reconstruir as configurações; 10. validar as configurações geradas; 11. mover o diretório para o local definitivo; 12. recarregar editor e publicador; 13. testar URLs; 14. registrar a operação; 15. entregar credenciais e documentação. ### Recarregar sem derrubar uploads Depois de alterar apenas contas ou volumes: ```bash sudo docker kill --signal=USR1 webtilde-editor sudo docker kill --signal=USR1 webtilde-pages ``` Mudanças globais exigem recriação ou reinício controlado: ```bash cd /opt/webtilde sudo docker compose up -d --force-recreate editor pages ``` ### Suspensão Suspender não significa apagar imediatamente. O script deve: - marcar `status=suspended` no registro; - remover a conta do editor; - remover ou substituir o volume público por página de suspensão; - manter os arquivos preservados; - recarregar a configuração; - registrar motivo e data; - definir prazo de recurso ou remoção. ### Remoção A remoção definitiva deve exigir uma segunda ação administrativa e um backup anterior. Fluxo recomendado: ```text 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. --- ## Portal comunitário O copyparty cuida dos arquivos, mas não cria sozinho a cultura da comunidade. Um pequeno gerador estático deve construir o portal. ### Páginas mínimas ```text / /about/ /join/ /rules/ /help/ /members/ /recent/ /random/ /projects/ webring/ feed.xml ``` ### Diretório de membros Cada entrada pode exibir: - nome público; - `~username`; - título extraído do HTML; - descrição opcional; - data da última atualização; - tags escolhidas pelo membro; - link para o site; - indicação de novo membro. Não exiba e-mail, IP, quota, nome civil obrigatório ou estatísticas invasivas. ### Atualizações recentes 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: - ignorar alterações de arquivos temporários; - agrupar várias mudanças do mesmo membro; - não revelar nomes de arquivos privados; - limitar uma entrada por membro em cada janela de tempo; - não transformar atividade em ranking competitivo. ### Página aleatória 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. ### Webring Cada site inicial recebe links “anterior”, “aleatório” e “próximo”. O gerador recalcula a ordem a partir dos membros ativos. ### RSS coletivo O feed deve publicar somente eventos de atualização, por exemplo: ```text 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. --- ## Experiência do membro ### Primeiro acesso O membro recebe: ```text 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: 1. entrar no editor; 2. abrir `index.html`; 3. alterar título e apresentação; 4. salvar; 5. abrir a página pública; 6. editar `style.css`; 7. adicionar uma imagem otimizada. ### Fluxo cotidiano ```text 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. ### WebDAV opcional 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. --- ## Regras comunitárias mínimas A política precisa ser curta o bastante para ser lida e clara o bastante para ser aplicada. ### Permitido - páginas pessoais; - projetos experimentais; - ensaios, diários e blogs estáticos; - arte digital; - coleções pequenas e legais; - CSS estranho; - estética retro, minimalista ou maximalista; - links para outros espaços pessoais; - conteúdo em qualquer idioma, desde que moderável. ### Proibido - malware; - phishing; - mineração no navegador; - rastreamento abusivo; - hospedagem de material ilegal; - assédio e exposição de dados pessoais; - cópia massiva de conteúdo protegido; - usar a quota como CDN comercial; - uso como espelho de backups; - tentativa de explorar outros membros ou a infraestrutura; - páginas que falsifiquem o login da comunidade. ### Privacidade Deixe explícito: - administradores conseguem acessar arquivos hospedados; - os sites são públicos; - logs técnicos existem; - backups retêm versões por período definido; - não existe promessa de anonimato forte; - o serviço não deve receber segredos ou documentos privados. --- ## Monitoramento ### O que observar - estado dos dois containers; - respostas HTTP do editor e do publicador; - espaço livre; - tamanho total dos sites; - quantidade de arquivos; - falhas de login; - erros 5xx; - tempo de resposta; - filas ou uploads incompletos; - alterações inesperadas de configuração; - presença de symlinks perigosos; - resultado do backup mais recente; - idade do último teste de restauração. ### Alertas mínimos - disco abaixo de 15% livre; - container reiniciando repetidamente; - domínio sem responder; - backup diário ausente; - certificado próximo do vencimento; - aumento anormal de tráfego; - alteração do registro de membros fora do processo normal; - arquivo maior que o permitido aparecendo no filesystem. Logs sem revisão são decoração técnica. Defina retenção e alertas desde o piloto. --- ## Backup e restauração ### O que precisa ser salvo ```text /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. ### Política inicial | 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 | ### Teste real Uma restauração válida não é “o comando terminou sem erro”. Ela deve comprovar: 1. recuperação de um usuário específico; 2. recuperação do registro; 3. reconstrução das configurações; 4. inicialização dos containers; 5. acesso ao site restaurado; 6. login no editor; 7. preservação de proprietário e permissões. --- ## Atualizações ### Política - fixar versão da imagem; - acompanhar releases e advisories; - testar atualização em cópia ou ambiente de staging; - ler mudanças de configuração; - fazer backup antes da atualização; - atualizar um componente por vez; - validar login, upload, publicação e quotas; - manter procedimento de rollback. ### Procedimento sugerido ```bash 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. --- ## Plano de testes ### Isolamento entre usuários - Alice não vê o volume de Bruno; - Alice não baixa arquivo de Bruno pelo editor; - Alice não move arquivo para pasta de Bruno; - URL manipulada manualmente retorna negação; - conta suspensa perde acesso imediatamente. ### Publicação - `index.html` é entregue na raiz do usuário; - não existe listagem de diretórios; - CSS e imagens carregam; - página sem `index.html` falha de maneira previsível; - arquivos proibidos são bloqueados; - JavaScript não executa no piloto. ### Permissões do container - o publicador não consegue criar arquivo; - nenhum container enxerga `/etc` do host; - nenhum container recebe socket Docker; - processo roda com UID/GID do usuário `webtilde`; - capacidades Linux foram removidas; - portas internas escutam apenas em loopback. ### Quotas - arquivo acima de 25 MiB é rejeitado; - volume acima de 100 MiB é bloqueado; - volume acima de 2.000 arquivos é bloqueado; - reserva mínima de disco é respeitada; - rejeição não corrompe arquivos existentes. ### Proxy - HTTP redireciona para HTTPS; - IP real aparece corretamente nos logs; - upload grande não falha por buffering; - cabeçalho CSP chega intacto ao navegador; - HSTS só é ativado depois que todos os subdomínios estiverem corretos; - portas 3923 e 3924 não são acessíveis externamente. ### Recuperação - apagar um arquivo e restaurá-lo; - restaurar um site completo; - reconstruir container em host limpo; - recriar configuração a partir do registro; - medir o tempo real de recuperação. --- ## Fases do projeto ### Fase 0 — prova local Duração sugerida: 1 a 3 dias. Objetivos: - duas instâncias funcionando; - um usuário fictício; - proxy local ou hosts file; - `nohtml`, `noscript` e `h` validados; - tentativa de acesso cruzado testada; - configuração descartável. Critério de saída: arquitetura comprovada sem domínio público. ### Fase 1 — alpha fechado Duração sugerida: 30 dias. Escopo: - 5 a 10 membros conhecidos; - aprovação manual; - 100 MiB por membro; - HTML e CSS; - JavaScript bloqueado; - portal comunitário básico; - backup diário; - canal único de suporte. Critérios de sucesso: - pelo menos 80% publicam sem intervenção manual longa; - nenhum acesso cruzado; - nenhum incidente crítico; - restauração testada; - onboarding administrativo abaixo de cinco minutos; - documentação resolve as dúvidas mais repetidas. ### Fase 2 — beta público controlado Escopo: - formulário de inscrição; - fila de aprovação; - termos e política de privacidade; - automação de contas; - página de status; - moderação documentada; - métricas e alertas; - até 50 membros. Critério de saída: processo sustentável sem depender de improviso diário do administrador. ### Fase 3 — subdomínios por membro Modelo: ```text alice.pages.runv.club bruno.pages.runv.club ``` Benefícios: - origem separada por membro; - possibilidade de JavaScript com risco reduzido entre usuários; - cookies e armazenamento local isolados; - identidade mais forte para os sites. Custos: - wildcard DNS e certificado; - roteamento por hostname; - validação mais rigorosa de nomes; - mais testes de cache, CSP e proxy; - prevenção de subdomínios reservados. JavaScript só deve ser considerado depois dessa fase. ### Fase 4 — ponte para uma tilde Unix real A comunidade pode ganhar contas Debian e SSH mantendo o copyparty como interface opcional. ```text /home/alice/public_html ▲ ▲ │ │ SSH copyparty ``` Essa fase adiciona: - usuários Unix reais; - shell; - Git; - editores de terminal; - quotas de filesystem; - limites de processos; - política de execução; - maior superfície de abuso. Não tente implementar isso no mesmo dia da Webtilde. São produtos operacionalmente diferentes. --- ## Riscos e respostas | 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 | --- ## Decisões que eu não recomendo - uma única instância para editar e servir; - usar `latest` sem revisão; - permitir upload anônimo; - liberar JavaScript na origem compartilhada; - montar o disco inteiro no container; - rodar como root; - abrir todos os protocolos do copyparty; - oferecer 5 ou 10 GiB por usuário sem necessidade; - gerar configuração manualmente para dezenas de membros; - confiar em backup nunca restaurado; - chamar o experimento de “tilde Unix completa” quando não existe shell; - adicionar banco, painel React e fila de jobs antes de provar o fluxo básico. 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. --- ## Métricas de sucesso ### Técnicas - disponibilidade mensal; - tempo médio de criação de conta; - quantidade de erros de permissão; - taxa de sucesso de upload; - restaurações testadas; - uso de disco por membro; - número de incidentes de segurança; - tempo de atualização da configuração. ### Comunitárias - membros que alteraram o site inicial; - páginas atualizadas no último mês; - visitas pelo botão aleatório; - participação em projetos coletivos; - inscrições aprovadas que realmente publicaram; - dúvidas recorrentes que indicam falha de documentação; - membros que continuam ativos após 30 e 90 dias. 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. --- ## Checklist de abertura ### Infraestrutura - [ ] Debian atualizado - [ ] Docker e Compose instalados - [ ] usuário `webtilde` sem shell - [ ] filesystem com espaço e monitoramento - [ ] portas internas apenas em loopback - [ ] proxy reverso com TLS - [ ] dois containers separados - [ ] container público com volume somente leitura - [ ] nenhum socket Docker montado ### Segurança - [ ] `nohtml` no editor - [ ] `noscript` no publicador - [ ] permissão `h` nos sites - [ ] prologues e README automáticos desabilitados - [ ] contas com hashes - [ ] teste de acesso cruzado concluído - [ ] CSP verificada no navegador - [ ] quotas funcionando - [ ] versão sem advisory crítico conhecido ### Operação - [ ] script de criação testado - [ ] suspensão testada - [ ] remoção com arquivo testada - [ ] backup externo concluído - [ ] restauração real concluída - [ ] logs e alertas funcionando - [ ] procedimento de atualização documentado - [ ] contato de suporte definido ### Comunidade - [ ] nome e descrição honestos - [ ] regras publicadas - [ ] privacidade publicada - [ ] tutorial inicial curto - [ ] site modelo editável - [ ] diretório de membros - [ ] páginas recentes - [ ] página aleatória - [ ] webring - [ ] formulário ou processo de inscrição --- ## Detalhes recolhíveis
Por que não usar volumes dinâmicos por identidade no primeiro dia? O 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.
Por que duas instâncias em vez de apenas dois volumes? Volumes separam caminhos e permissões, mas não criam o mesmo grau de isolamento operacional de processos diferentes. Com duas instâncias: - a pública não possui credenciais; - a pública recebe bind mount somente leitura; - políticas globais podem ser diferentes; - falha no editor não implica automaticamente escrita pelo publicador; - logs e atualizações podem ser analisados separadamente; - o proxy distingue claramente os dois papéis. 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.
Quando liberar JavaScript? Somente quando cada membro tiver uma origem independente, idealmente um subdomínio próprio, e depois de validar: - wildcard DNS; - certificado wildcard ou automação equivalente; - isolamento de cookies; - CSP por site; - política contra mineração e rastreamento; - bloqueio de phishing; - resposta a abuso; - limites de rede e armazenamento. 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.
Rollback da implantação ```bash cd /opt/webtilde sudo docker compose down ``` Esse comando remove os containers e a rede do Compose, mas não deve apagar: ```text /srv/webtilde/users/ /opt/webtilde/config/ /opt/webtilde/state/ /opt/webtilde/registry/ ``` Antes de qualquer remoção definitiva: ```bash 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.
--- ## Fontes técnicas consultadas A pesquisa para este plano foi baseada principalmente em fontes primárias: - repositório oficial `9001/copyparty`; - README oficial do copyparty; - documentação oficial de contas, volumes e permissões; - documentação oficial das imagens Docker; - exemplos oficiais de proxy reverso; - releases e avisos de segurança do projeto; - documentação do Tilde.club sobre computador Unix compartilhado, páginas pessoais e comunidade; - documentação oficial do Docker para Debian e Docker Compose. Pontos incorporados diretamente ao desenho: - contas e permissões por volume; - permissão `h` para comportamento de servidor web; - `nohtml` e `noscript` para conteúdo não confiável; - quotas `sz`, `df`, `vmaxb` e `vmaxn`; - necessidade de `e2ds` para limites totais do volume; - recarga de contas e volumes por `USR1`; - uso da imagem Docker `copyparty/ac`; - uso de `/cfg` para configurações e `/w` para conteúdo; - recomendação de proxy reverso; - acompanhamento de releases e vulnerabilidades. ### Limite desta documentação 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. --- ### Dicas finais - **Comece com dez pessoas, não cem**: a parte difícil não é subir o container; é operar comunidade, abuso, restauração e suporte. - **Não libere JavaScript por ansiedade de parecer completo**: HTML e CSS bastam para provar a ideia. - **Não misture editor e sites públicos**: essa separação deve existir desde a primeira implantação. - **Use um registro como fonte de verdade**: configuração gerada é descartável; dados dos membros e registro não são. - **Teste restauração antes de convidar pessoas**: depois que alguém cria algo, o projeto passa a ter responsabilidade real. - **Chame de Webtilde**: é inspirado em tilde, mas não finge oferecer shell Unix. - **Preserve o caminho para crescer**: a mesma pasta `public_html` poderá futuramente ser acessada por SSH em uma tilde Debian real. - **Resista à plataforma infinita**: diretório, página aleatória, webring e bons sites importam mais que um painel administrativo gigantesco. 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.