It works!

This is the default welcome page used to test the correct operation of the Apache2 server after installation on Debian systems. If you can read this page, it means that the Apache HTTP server installed at this site is working properly. You should replace this file (located at /var/www/html/index.html) before continuing to operate your HTTP server.

If you are a normal user of this web site and don't know what this page is about, this probably means that the site is currently unavailable due to maintenance. If the problem persists, please contact the site's administrator.

Configuration Overview

Debian's Apache2 default configuration is different from the upstream default configuration, and split into several files optimized for interaction with Debian tools. The configuration system is fully documented in /usr/share/doc/apache2/README.Debian.gz. Refer to this for the full documentation. Documentation for the web server itself can be found by accessing the manual if the apache2-doc package was installed on this server.

The configuration layout for an Apache2 web server installation on Debian systems is as follows:

/etc/apache2/
|-- apache2.conf
|       `--  ports.conf
|-- mods-enabled
|       |-- *.load
|       `-- *.conf
|-- conf-enabled
|       `-- *.conf
|-- sites-enabled
|       `-- *.conf
          
  • apache2.conf is the main configuration file. It puts the pieces together by including all remaining configuration files when starting up the web server.
  • ports.conf is always included from the main configuration file. It is used to determine the listening ports for incoming connections, and this file can be customized anytime.
  • Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/ directories contain particular configuration snippets which manage modules, global configuration fragments, or virtual host configurations, respectively.
  • They are activated by symlinking available configuration files from their respective *-available/ counterparts. These should be managed by using our helpers a2enmod, a2dismod, a2ensite, a2dissite, and a2enconf, a2disconf . See their respective man pages for detailed information.
  • The binary is called apache2. Due to the use of environment variables, in the default configuration, apache2 needs to be started/stopped with /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not work with the default configuration.
Document Roots

By default, Debian does not allow access through the web browser to any file apart of those located in /var/www, public_html directories (when enabled) and /usr/share (for web applications). If your site is using a web document root located elsewhere (such as in /srv) you may need to whitelist your document root directory in /etc/apache2/apache2.conf.

The default Debian document root is /var/www/html. You can make your own virtual hosts under /var/www. This is different to previous releases which provides better security out of the box.

Reporting Problems

Please use the reportbug tool to report bugs in the Apache2 package with Debian. However, check existing bug reports before reporting a new bug.

Please report bugs specific to modules (such as PHP and others) to respective packages, not to the web server itself.

// Widget de Chat ZPRO (function() { // Cria o elemento do widget const widgetHTML = `

WEBChat

`; // Adiciona o widget ao documento document.body.insertAdjacentHTML('beforeend', widgetHTML); // Inicializa o widget const chatButton = document.getElementById('zpro-chat-button'); const chatContainer = document.getElementById('zpro-chat-container'); const chatClose = document.getElementById('zpro-chat-close'); const chatClear = document.getElementById('zpro-chat-clear'); const messagesDiv = document.getElementById('zpro-chat-messages'); const messageInput = document.getElementById('zpro-chat-input'); const sendButton = document.getElementById('zpro-chat-send'); const sessionSpan = document.getElementById('zpro-chat-session'); const widgetDiv = document.getElementById('zpro-chat-widget'); // Variáveis globais para sessão e token let webchatId = null; let token = null; let ws = null; let chatLoaded = false; // Funções de controle do widget chatButton.addEventListener('click', async () => { chatContainer.classList.add('show'); if (!chatLoaded) { await loadMessageHistory(); connectWebSocket(); chatLoaded = true; } }); chatClose.addEventListener('click', () => { chatContainer.classList.remove('show'); }); // Função para gerar ID único de sessão function generateUniqueId() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 8); return `${timestamp}-${random}`; } function generateSessionId() { if (!sessionStorage.getItem('zproWebchatId')) { sessionStorage.setItem('zproWebchatId', generateUniqueId()); } return sessionStorage.getItem('zproWebchatId'); } // Função para registrar o usuário no backend async function registerWebchat() { webchatId = generateSessionId(); const name = 'WebChat ' + webchatId; const email = 'webchat@webchat.com'; const tenantId = '1'; const wabaId = '00b57702-fc38-46a7-b55d-8af7d3c998df'; const websocketToken = '80f0a22f-4156-4700-9142-b172eafd2e70'; console.log('[WebChat] Registrando sessão:', { webchatId, name, email, tenantId, wabaId }); const response = await fetch(`https://backizing.numem.com.br/webchat/register/${wabaId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-websocket-token': websocketToken }, body: JSON.stringify({ webchatId, name, email, tenantId }) }); const data = await response.json(); token = data.token; console.log('[WebChat] Sessão registrada:', { webchatId, token }); return { webchatId, token }; } // Exibe o ID da sessão async function showSessionId() { const { webchatId } = await registerWebchat(); sessionSpan.textContent = `Sessão: ${webchatId}`; } showSessionId(); // Função para formatar hora function formatTime(dateString) { const date = new Date(dateString); return date.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }); } // Função para formatar texto estilo WhatsApp function formatWhatsapp(text) { return text.replace(/\*(.*?)\*/g, '$1'); } // Função para adicionar mensagem function appendMessage(text, type, time = '', ack = null, id = null) { const messageDiv = document.createElement('div'); if (id) messageDiv.id = 'msg-' + id; messageDiv.className = `zpro-message ${type}`; let ackHtml = ''; if (type === 'zpro-sent' && ack !== null && ack !== undefined) { ackHtml = `${getAckIcon(ack)}`; } messageDiv.innerHTML = `${formatWhatsapp(text)}
${time} ${ackHtml}`; messagesDiv.appendChild(messageDiv); messagesDiv.scrollTop = messagesDiv.scrollHeight; } // Função para atualizar o ack de uma mensagem function updateMessageAck(messageId, ack) { const msgDiv = document.getElementById('msg-' + messageId); if (msgDiv) { const ackSpan = msgDiv.querySelector('.zpro-ack'); if (ackSpan) { ackSpan.innerHTML = getAckIcon(ack); } } } // Função para obter ícone do ack function getAckIcon(ack) { if (ack === 0) return '🕓'; if (ack === 1) return '✔️'; if (ack === 2) return '✔️'; if (ack === 3) return '✔️✔️'; if (ack === -1) return '❌'; return ''; } // Função para renderizar o histórico completo function renderHistory(messages) { messagesDiv.innerHTML = ''; messages.forEach(msg => { appendMessage( msg.body, msg.fromMe ? 'zpro-received' : 'zpro-sent', formatTime(msg.createdAt), msg.ack, msg.id ); }); } // Função para carregar histórico de mensagens async function loadMessageHistory() { try { const wabaId = '00b57702-fc38-46a7-b55d-8af7d3c998df'; const websocketToken = '80f0a22f-4156-4700-9142-b172eafd2e70'; const response = await fetch(`https://backizing.numem.com.br/webchat/messages/${wabaId}?from=${webchatId}&tenantId=1`, { headers: { 'x-websocket-token': websocketToken } }); const data = await response.json(); console.log('[WebChat] Histórico carregado:', data); if (Array.isArray(data)) { renderHistory(data); } else { console.warn('[WebChat] Resposta da API não é um array:', data); } } catch (error) { console.error('[WebChat] Erro ao carregar histórico:', error); } } // Função para gerar um ID temporário para mensagens enviadas function generateTempId() { return 'temp-' + Math.random().toString(36).substr(2, 9); } // Função para atualizar o ID de uma mensagem no DOM function updateMessageId(tempId, realId) { const tempDiv = document.getElementById('msg-' + tempId); if (tempDiv) { tempDiv.id = 'msg-' + realId; } } // Event listeners para envio de mensagem sendButton.addEventListener('click', async () => { const message = messageInput.value.trim(); if (message) { const tempId = generateTempId(); appendMessage(message, 'zpro-sent', formatTime(new Date().toISOString()), 0, tempId); messageInput.value = ''; const data = { body: message, from: webchatId, name: webchatId, email: webchatId + '@webchat.com', tenantId: '1', event: 'messages.upsert', fromMe: false, channel: 'webchat', type: 'webchat', webchatId: webchatId }; console.log('[WebChat] Enviando mensagem:', data); try { const wabaId = '00b57702-fc38-46a7-b55d-8af7d3c998df'; const websocketToken = '80f0a22f-4156-4700-9142-b172eafd2e70'; const response = await fetch(`https://backizing.numem.com.br/webchat-webhook/${wabaId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-websocket-token': websocketToken }, body: JSON.stringify(data) }); const respData = await response.json(); console.log('[WebChat] Resposta do backend:', respData); if (respData && respData.id) { updateMessageId(tempId, respData.id); } } catch (error) { console.error('[WebChat] Erro ao enviar mensagem:', error); } } }); messageInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { sendButton.click(); } }); // WebSocket para receber mensagens e ack em tempo real function connectWebSocket() { if (!webchatId || !token) return; let pingInterval; let historyInterval; let reconnectAttempts = 0; const MAX_RECONNECT_ATTEMPTS = 5; const RECONNECT_DELAY = 5000; const PING_INTERVAL = 30000; const HISTORY_INTERVAL = 60000; function connect() { const wabaId = '00b57702-fc38-46a7-b55d-8af7d3c998df'; const websocketToken = '80f0a22f-4156-4700-9142-b172eafd2e70'; ws = new WebSocket(`wss://webchat.numem.com.br/wss?from=${webchatId}&token=${token}`); ws.onopen = () => { console.log('[WebChat] WebSocket conectado!'); reconnectAttempts = 0; pingInterval = setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'ping' })); } }, PING_INTERVAL); historyInterval = setInterval(async () => { if (ws.readyState === WebSocket.OPEN) { console.log('[WebChat] Buscando histórico periodicamente...'); await loadMessageHistory(); } }, HISTORY_INTERVAL); }; ws.onmessage = (event) => { try { const data = JSON.parse(event.data); console.log('[WebChat] Evento recebido do backend:', data); if (data.type === 'webhook' && data.payload && data.payload.message) { const msg = data.payload.message; appendMessage( msg.body, 'zpro-received', formatTime(msg.createdAt), msg.ack, msg.id ); } if (data.type === 'ack_update' && data.payload) { updateMessageAck(data.payload.messageId, data.payload.ack); } if (data.type === 'pong') { console.log('[WebChat] Pong recebido'); } } catch (error) { console.error('[WebChat] Erro ao processar mensagem WebSocket:', error); } }; ws.onerror = (error) => { console.error('[WebChat] Erro na conexão WebSocket:', error); }; ws.onclose = () => { console.log('[WebChat] Conexão WebSocket fechada'); clearInterval(pingInterval); clearInterval(historyInterval); if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) { reconnectAttempts++; console.log(`[WebChat] Tentando reconectar (tentativa ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`); setTimeout(connect, RECONNECT_DELAY); } else { console.error('[WebChat] Número máximo de tentativas de reconexão atingido'); } }; } connect(); } // Função para limpar a sessão async function clearSession() { if (confirm('Tem certeza que deseja limpar a sessão e começar uma nova conversa?')) { messagesDiv.innerHTML = ''; sessionStorage.removeItem('zproWebchatId'); if (ws) { ws.close(); } webchatId = null; token = null; chatLoaded = false; await showSessionId(); await loadMessageHistory(); connectWebSocket(); } } chatClear.addEventListener('click', clearSession); })();