Generación de configuraciones para nginx, la historia de un pull request

Saludos, compañeros. En mis servidores de batalla ha estado funcionando desde 2006 y a lo largo de los años de su administración he acumulado muchos configuraciones y plantillas. He elogiado mucho nginx y de alguna manera terminé creando un hub de nginx en Habr también, ¡qué presunción! nginx Los amigos me pidieron que levantara una granja de desarrollo y en lugar de llevarles mis plantillas específicas, recordé un proyecto interesante
nginxconfig.io , que distribuye configuraciones y prepara todo para lets encrypt, etc. Pensé, ¿por qué no? Sin embargo, me molestó el hecho de que nginxconfig me invita a descargar un archivo zip en el navegador, sin permitirme enviarlo directamente al servidor usando wget/fetch/curl. ¿Qué tontería es esta? Lo necesito en el servidor desde la consola. Enfurecido, fui a github a ver las tripas del proyecto, lo que llevó a su bifurcación y, como resultado, a un pull request. No habría escrito sobre esto si no hubiera sido interesante 😉Por supuesto, antes de hurgar en los fuentes, miré desde dónde Chrome obtiene el archivo zip generado con las configuraciones, y encontré una dirección que comienza con "blob:", oh. Ya estaba claro que el servicio no genera nada, de hecho, lo hace todo el js. De hecho, el archivo zip lo genera el cliente, el navegador, javascript. Es decir, la belleza de esto es que el proyecto

Generación de configuraciones para nginx, la historia de un pull request

puede ser simplemente guardado como una página html, subido a algún , que distribuye configuraciones y prepara todo para lets encrypt, etc. Pensé, ¿por qué no? Sin embargo, me molestó el hecho de que nginxconfig me invita a descargar un archivo zip en el navegador, sin permitirme enviarlo directamente al servidor usando wget/fetch/curl. ¿Qué tontería es esta? Lo necesito en el servidor desde la consola. Enfurecido, fui a github a ver las tripas del proyecto, lo que llevó a su bifurcación y, como resultado, a un pull request. No habría escrito sobre esto si no hubiera sido interesante 😉 narod.ru y funcionará ) Es una solución muy divertida e interesante, sin embargo, es terriblemente incómoda para la configuración de servidores, precisamente para eso fue creado este proyecto. ¿Descargar el archivo zip generado por el navegador y luego transferirlo al servidor usando nc… en 2019? Me planteé el reto de encontrar una forma de descargar la configuración obtenida directamente en el servidor. Al hacer una bifurcación del proyecto, empecé a pensar en qué opciones tenía. La tarea se complicaba porque no quería apartarme de la condición de que el proyecto debía permanecer como un front-end limpio, sin ningún back-end. Por supuesto, la solución más simple habría sido introducir nodejs y hacer que generara un archivo zip con las configuraciones a partir de enlaces directos.
En realidad, las opciones no eran muchas. De hecho, solo se me ocurrió una. Necesitamos configurar las configuraciones y obtener un enlace que podamos copiar en la consola del servidor para obtener el archivo zip.
Las opciones no eran muchas. De hecho, solo se me ocurrió una. Necesitamos configurar los archivos de configuración y obtener un enlace que podamos copiar en la consola del servidor para recibir el archivo zip.
Varios archivos de texto en el archivo zip recibido pesaban muy poco, apenas unos cuantos kilobytes. La solución obvia fue obtener una cadena base64 del archivo zip generado y lanzarla al portapapeles, mientras que en el servidor se ejecutaba un comando en la consola.

echo 'base64string' | base64 --decode > config.zip

podríamos crear ese archivo zip.

, que distribuye configuraciones y prepara todo para lets encrypt, etc. Pensé, ¿por qué no? Sin embargo, me molestó el hecho de que nginxconfig me invita a descargar un archivo zip en el navegador, sin permitirme enviarlo directamente al servidor usando wget/fetch/curl. ¿Qué tontería es esta? Lo necesito en el servidor desde la consola. Enfurecido, fui a github a ver las tripas del proyecto, lo que llevó a su bifurcación y, como resultado, a un pull request. No habría escrito sobre esto si no hubiera sido interesante 😉 fue escrito en AngularJS, no me imagino cuántos kilómetros de código se necesitarían si el autor no hubiera elegido un marco reactivo de js. Pero sí imagino lo mucho más fácil y hermoso que podría haber sido implementar todo esto en VueJS, aunque eso ya es otro tema.
En las fuentes del proyecto vemos el método de generación del archivo zip:

$scope.downloadZip = function() {
	var zip = new JSZip();

	var sourceCodes = $window.document.querySelectorAll('main .file .code.source');

	for (var i = 0; i < sourceCodes.length; i++) {
		var sourceCode = sourceCodes[i];

		var name	= sourceCode.dataset.filename;
		var content	= sourceCode.children[0].children[0].innerText;

		if (!$scope.isSymlink() && name.match(/^sites-available\/)) {
			name = name.replace(/^sites-available\/, 'sites-enabled\/');
		}

		zip.file(name, content);

		if (name.match(/^sites-available\/)) {
			zip.file(name.replace(/^sites-available\/, 'sites-enabled\/'), '..\/ ' + name, {
				unixPermissions: parseInt('120755', 8),
			});
		}
	}

	zip.generateAsync({
		type: 'blob',
		platform: 'UNIX',
	}).then(function(content) {
		saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_zip',
	});
};

todo es bastante simple, utilizando la biblioteca jszip se crea un zip, donde se colocan los archivos de configuración. Después de crear el archivo zip, js lo alimenta al navegador utilizando la biblioteca FileSaver.js:

saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');

donde content es el objeto blob obtenido del archivo zip.

Bien, todo lo que tenía que hacer era agregar otro botón al lado y al hacer clic en él, no guardar el archivo zip obtenido en el navegador, sino obtener su código base64. Después de experimentar un poco, obtuve 2 métodos en lugar de uno downloadZip:

$scope.downloadZip = function() {
	generateZip(function (content) {
		saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_zip',
	});
};
$scope.downloadBase64 = function() {
	generateZip(function (content) {
		var reader = new FileReader();
		reader.readAsDataURL(content);
		reader.onloadend = function() {
			var base64 = reader.result.replace(/^data:.+;base64,/, '');
			// en la variable base64 está justo el archivo zip que necesito en forma de cadena base64
		}
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_base64',
	});
};

Como pudieron notar, la generación del archivo zip la he trasladado a un método privado llamado generateZip. Y dado que esto es AngularJS, y el autor se adhiere a los callbacks, no decidí implementarlo a través de promesas. downloadZip todavía hacía saveAs al final, mientras que downloadBase64 hacía algo un poco diferente. Creamos un objeto FileReader, que llegó a nosotros con html5 y ya es bastante disponible para usar. Que, en su momento, sabe hacer de blob una cadena base64, más exactamente, genera una cadena DataURL, pero eso no es tan importante, ya que DataURL contiene exactamente lo que necesitamos. Bingo, un pequeño obstáculo me estaba esperando al intentar colocar todo esto en el portapapeles. El autor utilizó en el proyecto la biblioteca clipboardjs, que permite trabajar con el portapapeles sin objetos flash, basado en el texto seleccionado. Inicialmente decidí colocar mi base64 en un elemento con display:none;, pero en ese caso no podía colocarlo en el portapapeles, ya que no se produce la selección. Así que, en lugar de display:none;, hice

position: absolute;
z-index: -1;
opacity: 0;

lo que me permitió ocultar el elemento de la vista y, de hecho, dejarlo en la página. Voilà, tarea cumplida, al hacer clic en mi botón, la cadena iba al portapapeles con la siguiente forma:

echo 'base64string' | base64 --decode > config.zip

que simplemente pegaba en la consola del servidor y obtenía de inmediato el archivo zip con todas las configuraciones.
Y, por supuesto, envié un pull request al autor, ya que el proyecto está activo y vivo, quiero ver actualizaciones del autor y tener mi botón también. Para quienes estén interesados, aquí está mi fork del proyecto y el propio pull request, donde se puede ver lo que corregí/complementé.
¡A todos, feliz desarrollo!)

Generación de configuraciones para nginx, la historia de un pull request

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster