Despliega tu propio servidor PrivateBin colaborativo y seguro en Kubernetes

Despliega tu propio servidor PrivateBin colaborativo y seguro en Kubernetes

¿Te gustaría ofrecer a tus usuarios un servicio de notas colaborativas instantáneas, totalmente privado, sin depender de plataformas externas como Pastebin o Google Docs rápidos? Hoy desplegamos PrivateBin en Kubernetes: una app de moda para compartir texto colaborativamente en tiempo real, con cifrado extremo a extremo. Además, añadiremos autenticación opcional, almacenamiento persistente y HTTPS con Cert-Manager. ¡Nivel intermedio-avanzado y utilidad real para equipos y comunidades!

¿Qué es PrivateBin y por qué lo usarías?

  • Plataforma de pegado (“pastebin”) privado: Los mensajes se cifran en el navegador antes de subirlos al servidor; el administrador jamás ve los textos “en claro”.
  • Ideal para equipos, bug reporting, entornos DevSecOps: Comparte logs, credenciales temporales o código sensible sin escapar de tu propia infraestructura.
  • Apoyado por la comunidad de ciberseguridad: Es el sustituto recomendado de pads inseguros para compartir secreto entre equipos.

Hoy lo montamos con:

  • Autenticación básica (evitando abusos públicos)
  • HTTPS automático con Cert-Manager
  • Almacenamiento persistente en un PVC (para adjuntos o logs)
  • Despliegue escalable (replicas controladas por Deployment)

Arquitectura Kubernetes

Esquema pod Kubernetes

Nuestro stack será sencillo pero robusto:

  • 1 Service de tipo ClusterIP
  • 1 Deployment (PrivateBin con sidecar nginx para autenticación básica)
  • 1 Ingress con anotaciones para Cert-Manager e integración HTTPS automática
  • 1 PersistentVolumeClaim (almacenamiento de archivos o logs, configurable)

¿No tienes Cert-Manager? Puedes saltarte las anotaciones del Ingress y usar un Ingress Controller con TLS manual.

Ficheros YAML completos del despliegue

ConfigMap: configuración personalizada de PrivateBin

apiVersion: v1
kind: ConfigMap
metadata:
  name: privatebin-config
data:
  conf.php: |
    <?php
    return [
      "expire" => "1d",
      "fileupload" => true,
      "sizelimit" => 10485760,
      "opendiscussion" => true,
      "password" => true,
      "burnafterreading" => true,
      "formatter" => "markdown",
    ];
    ?>

PVC: almacenamiento persistente

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: privatebin-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

Deployment: PrivateBin + Nginx con autenticación básica

apiVersion: apps/v1
kind: Deployment
metadata:
  name: privatebin
spec:
  replicas: 2
  selector:
    matchLabels:
      app: privatebin
  template:
    metadata:
      labels:
        app: privatebin
    spec:
      containers:
        - name: privatebin
          image: privatebin/nginx-fpm-alpine:1.6.0
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: config
              mountPath: /srv/cfg/
            - name: storage
              mountPath: /srv/data
        - name: nginx-auth
          image: docker.io/nginx:alpine
          ports:
            - containerPort: 80
          volumeMounts:
            - name: htpasswd
              mountPath: /etc/nginx/conf.d/
          env:
            - name: PRIVATEBIN_UPSTREAM
              value: "localhost:8080"
      volumes:
        - name: config
          configMap:
            name: privatebin-config
            items:
            - key: conf.php
              path: conf.php
        - name: storage
          persistentVolumeClaim:
            claimName: privatebin-pvc
        - name: htpasswd
          secret:
            secretName: privatebin-htpasswd

Secret: usuario y password (htpasswd)

apiVersion: v1
kind: Secret
metadata:
  name: privatebin-htpasswd
data:
  htpasswd: |
    dXNlciRhcHI6JDEkNkhHT0o1eTh6TXhOZ0ZUZ3U5WUV0cG9OeUrgZW54LnJMejRLRytlR2JMSTZlQzEyVWNNUldEOGVDRG4wOQ==

La línea anterior es un htpasswd base64 con usuario “user☁️” y contraseña “changeme”. Genera el tuyo localmente en producción.

Service

apiVersion: v1
kind: Service
metadata:
  name: privatebin
spec:
  selector:
    app: privatebin
  ports:
    - port: 8080
      targetPort: 8080
      name: http

Ingress (cert-manager, HTTPS y path personalizado)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: privatebin-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  rules:
    - host: "paste.tudominio.com"
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: privatebin
                port:
                  number: 8080
  tls:
    - hosts:
        - "paste.tudominio.com"
      secretName: privatebin-tls

Recuerda sustituir paste.tudominio.com por el dominio que quieras usar; tendrás que crear el registro DNS adecuado.

¿Cómo lo despliego?

  1. Guarda cada bloque YAML en ficheros como configmap-privatebin.yaml, deployment.yaml
  2. Lanza kubectl apply -f en tu clúster, uno a uno.
  3. Comprueba que los pods y servicios levantan correctamente. Usa kubectl get pods,svc,ingress.
  4. ¡Accede al dominio configurado! Prueba a loguearte con el usuario y pass… y comparte tu paste seguro.

Consejos extra y troubleshooting

  • Error 502 Gateway: Comprueba que tanto PrivateBin como nginx sidecar están levantados. Loguéate a ambos contenedores usando kubectl exec -it para ver logs.
  • Problemas con volúmenes persistentes: Si el storage da error, prueba a borrar y recrear el PVC (ojo, perderás almacenado).
  • Personaliza el htpasswd: Usa htpasswd -nb user password | base64 y reemplaza en el Secret.
  • Para aumentar la seguridad: Activa firewall de red en el Ingress (NetworkPolicy), limita el acceso por IP, y activa alertas si detectas movimientos extraños.

Si quieres que tus pastes se autodestruyan, simplemente configura la opción burnafterreading como true en el configMap.


¿Te animas a compartir tu propio Pastebin cifrado en tu VPS? Adáptalo a tu flujo DevOps, ¡la privacidad mola!

¡Nos leemos en el siguiente proyecto Kubernetes!

Avatar

Por Mid