commit 36ca0e817aee6c459d126a18ce36b2232fb7bf0f Author: counterweight Date: Thu Oct 16 09:50:36 2025 +0200 app starts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c0975d0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM node:18-alpine + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm install --omit=dev + +# Copy application files +COPY . . + +# Create non-root user for security +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nodejs -u 1001 + +# Change ownership of the app directory +RUN chown -R nodejs:nodejs /app +USER nodejs + +# Expose port +EXPOSE 3000 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "require('http').get('http://localhost:3000', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })" + +# Start the application +CMD ["node", "server.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..c070f99 --- /dev/null +++ b/README.md @@ -0,0 +1,123 @@ +# Emergencia Pablo - Webapp de Mensajes + +Una aplicación web simple que permite a los usuarios enviar mensajes de emergencia a través de un servidor ntfy. + +## Características + +- Formulario simple con campos "Tu nombre" y "Mensaje" +- Envío automático a servidor ntfy con autenticación +- Interfaz minimalista y responsive +- Confirmación de envío al usuario + +## Instalación + +1. Instalar dependencias: +```bash +npm install +``` + +2. Configurar variables de entorno: +```bash +export NTFY_URL="https://tu-servidor-ntfy.com" +export NTFY_USER="tu-usuario" +export NTFY_PASSWORD="tu-password" +export PORT=3000 # opcional, por defecto 3000 +``` + +3. Ejecutar la aplicación: +```bash +npm start +``` + +## Variables de Entorno + +- `NTFY_URL`: URL de tu servidor ntfy (requerido) +- `NTFY_USER`: Usuario para autenticación en ntfy (requerido) +- `NTFY_PASSWORD`: Contraseña para autenticación en ntfy (requerido) +- `PORT`: Puerto donde correr la aplicación (opcional, por defecto 3000) + +## Uso + +1. Abre tu navegador en `http://localhost:3000` (o el puerto configurado) +2. Completa el formulario con tu nombre y mensaje +3. Haz clic en "Enviar Mensaje" +4. Recibirás confirmación si el mensaje se envió correctamente + +## Despliegue + +### Opción 1: Docker (Recomendado) + +1. Crea un archivo `.env` con tus credenciales: +```bash +NTFY_URL=https://tu-servidor-ntfy.com +NTFY_USER=tu-usuario +NTFY_PASSWORD=tu-password +``` + +2. Ejecuta con Docker Compose: +```bash +docker-compose up -d +``` + +La aplicación estará disponible en `http://localhost:3000` + +### Opción 2: Instalación directa + +Para desplegar en un servidor Linux: + +1. Sube los archivos al servidor +2. Instala Node.js (versión 14 o superior) +3. Configura las variables de entorno +4. Ejecuta `npm install` para instalar dependencias +5. Ejecuta `npm start` para iniciar la aplicación + +### Ejemplo con systemd (opcional) + +Crear archivo `/etc/systemd/system/emergenciapablo.service`: + +```ini +[Unit] +Description=Emergencia Pablo Webapp +After=network.target + +[Service] +Type=simple +User=tu-usuario +WorkingDirectory=/ruta/a/emergenciapablo +Environment=NTFY_URL=https://tu-servidor-ntfy.com +Environment=NTFY_USER=tu-usuario +Environment=NTFY_PASSWORD=tu-password +Environment=PORT=3000 +ExecStart=/usr/bin/node server.js +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +Luego: +```bash +sudo systemctl daemon-reload +sudo systemctl enable emergenciapablo +sudo systemctl start emergenciapablo +``` + +## Estructura del Proyecto + +``` +emergenciapablo/ +├── server.js # Servidor Express principal +├── package.json # Dependencias y scripts +├── Dockerfile # Configuración de Docker +├── docker-compose.yml # Orquestación con Docker Compose +├── public/ +│ ├── index.html # Página principal +│ └── style.css # Estilos CSS +└── README.md # Este archivo +``` + +## Notas + +- Los mensajes se envían al topic "Emergencia" en tu servidor ntfy +- El formato del mensaje es: "Nombre: Mensaje" +- La aplicación valida que ambos campos estén completos antes de enviar diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..226cae2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +services: + emergenciapablo: + build: . + container_name: emergenciapablo + ports: + - "3000:3000" + environment: + - NTFY_URL=${NTFY_URL} + - NTFY_USER=${NTFY_USER} + - NTFY_PASSWORD=${NTFY_PASSWORD} + - PORT=3000 + restart: unless-stopped + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s diff --git a/env.example b/env.example new file mode 100644 index 0000000..2d174ba --- /dev/null +++ b/env.example @@ -0,0 +1,4 @@ +# Copia este archivo a .env y configura tus valores +NTFY_URL=https://tu-servidor-ntfy.com +NTFY_USER=tu-usuario +NTFY_PASSWORD=tu-password diff --git a/package.json b/package.json new file mode 100644 index 0000000..c6304cc --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "emergenciapablo", + "version": "1.0.0", + "description": "Simple webapp to send messages via ntfy", + "main": "server.js", + "scripts": { + "start": "node server.js", + "dev": "node server.js" + }, + "dependencies": { + "express": "^4.18.2", + "axios": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..5f1949f --- /dev/null +++ b/public/index.html @@ -0,0 +1,72 @@ + + + + + + Mensaje de Emergencia + + + +
+

Mensaje de Emergencia

+
+
+ + +
+ +
+ + +
+ + +
+ + +
+ + + + diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..2794498 --- /dev/null +++ b/public/style.css @@ -0,0 +1,118 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background-color: #f5f5f5; + color: #333; + line-height: 1.6; +} + +.container { + max-width: 500px; + margin: 50px auto; + padding: 30px; + background: white; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +h1 { + text-align: center; + margin-bottom: 30px; + color: #2c3e50; + font-size: 24px; +} + +.form-group { + margin-bottom: 20px; +} + +label { + display: block; + margin-bottom: 5px; + font-weight: 500; + color: #555; +} + +input[type="text"], +textarea { + width: 100%; + padding: 12px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 16px; + font-family: inherit; +} + +input[type="text"]:focus, +textarea:focus { + outline: none; + border-color: #3498db; + box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2); +} + +textarea { + resize: vertical; + min-height: 100px; +} + +button { + width: 100%; + padding: 12px; + background-color: #3498db; + color: white; + border: none; + border-radius: 4px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s; +} + +button:hover:not(:disabled) { + background-color: #2980b9; +} + +button:disabled { + background-color: #bdc3c7; + cursor: not-allowed; +} + +.status { + margin-top: 20px; + padding: 12px; + border-radius: 4px; + text-align: center; + font-weight: 500; +} + +.status.success { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; +} + +.status.error { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} + +.status.hidden { + display: none; +} + +@media (max-width: 600px) { + .container { + margin: 20px; + padding: 20px; + } + + h1 { + font-size: 20px; + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..92845fe --- /dev/null +++ b/server.js @@ -0,0 +1,79 @@ +const express = require('express'); +const axios = require('axios'); +const path = require('path'); + +const app = express(); +const PORT = process.env.PORT || 3000; + +// Environment variables for ntfy configuration +const NTFY_URL = process.env.NTFY_URL; +const NTFY_USER = process.env.NTFY_USER; +const NTFY_PASSWORD = process.env.NTFY_PASSWORD; +const NTFY_TOPIC = 'Emergencia'; + +// Middleware +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); +app.use(express.static('public')); + +// Validate environment variables +if (!NTFY_URL || !NTFY_USER || !NTFY_PASSWORD) { + console.error('Missing required environment variables: NTFY_URL, NTFY_USER, NTFY_PASSWORD'); + process.exit(1); +} + +// Route to serve the main page +app.get('/', (req, res) => { + res.sendFile(path.join(__dirname, 'public', 'index.html')); +}); + +// Route to handle message submission +app.post('/send-message', async (req, res) => { + try { + const { name, message } = req.body; + + // Validate input + if (!name || !message) { + return res.status(400).json({ + success: false, + error: 'Nombre y mensaje son requeridos' + }); + } + + // Concatenate name and message + const fullMessage = `${name}: ${message}`; + + // Send to ntfy + const ntfyResponse = await axios.post(`${NTFY_URL}/${NTFY_TOPIC}`, fullMessage, { + auth: { + username: NTFY_USER, + password: NTFY_PASSWORD + }, + headers: { + 'Content-Type': 'text/plain' + } + }); + + if (ntfyResponse.status === 200) { + res.json({ success: true, message: 'Mensaje enviado correctamente' }); + } else { + res.status(500).json({ + success: false, + error: 'Error al enviar el mensaje' + }); + } + + } catch (error) { + console.error('Error sending message:', error.message); + res.status(500).json({ + success: false, + error: 'Error interno del servidor' + }); + } +}); + +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); + console.log(`Ntfy URL: ${NTFY_URL}`); + console.log(`Ntfy Topic: ${NTFY_TOPIC}`); +});