Diferencia entre revisiones de «LEMP»
Sin resumen de edición |
Sin resumen de edición |
||
| (No se muestran 9 ediciones intermedias del mismo usuario) | |||
| Línea 45: | Línea 45: | ||
* Instalación de servidor y cliente | * Instalación de servidor y cliente | ||
<syntaxhighlight lang="Bash">apt install mariadb-client mariadb-server</syntaxhighlight> | <syntaxhighlight lang="Bash">apt install mariadb-client mariadb-server mariadb-plugin-provider-bzip2 mariadb-plugin-provider-lz4 mariadb-plugin-provider-lzma mariadb-plugin-provider-lzo mariadb-plugin-provider-snappy</syntaxhighlight> | ||
* Inicializar base de datos | * Inicializar base de datos | ||
| Línea 148: | Línea 148: | ||
systemctl list-timers | grep certbot | systemctl list-timers | grep certbot | ||
Mon 2026-02-23 11:47:00 UTC 12h - - snap.certbot.renew.timer snap.certbot.renew.service | Mon 2026-02-23 11:47:00 UTC 12h - - snap.certbot.renew.timer snap.certbot.renew.service | ||
</syntaxhighlight> | |||
== Configuración PHP == | |||
* Configuración php-fpm: | |||
<syntaxhighlight lang="Bash">vi /etc/php/8.5/fpm/php.ini</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
[...] | |||
; Maximum amount of memory a script may consume | |||
; https://php.net/memory-limit | |||
memory_limit = 128M | |||
max_memory_limit = -1 | |||
[...] | |||
; Maximum size of POST data that PHP will accept. | |||
; Its value may be 0 to disable the limit. It is ignored if POST data reading | |||
; is disabled through enable_post_data_reading. | |||
; https://php.net/post-max-size | |||
post_max_size = 100M | |||
[...] | |||
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's | |||
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok | |||
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting | |||
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting | |||
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts | |||
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. | |||
; https://php.net/cgi.fix-pathinfo | |||
cgi.fix_pathinfo=0 | |||
[...] | |||
; Whether to allow HTTP file uploads. | |||
; https://php.net/file-uploads | |||
file_uploads = On | |||
[...] | |||
; Maximum allowed size for uploaded files. | |||
; https://php.net/upload-max-filesize | |||
upload_max_filesize = 100M | |||
[...] | |||
; Maximum number of files that can be uploaded via a single request | |||
max_file_uploads = 20 | |||
[...] | |||
[Session] | |||
; Handler used to store/retrieve data. | |||
; https://php.net/session.save-handler | |||
session.save_handler = files | |||
[...] | |||
</syntaxhighlight> | |||
* Configuración php-cli: | |||
<syntaxhighlight lang="Bash">vi /etc/php/8.5/cli/php.ini</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
[...] | |||
; Maximum amount of memory a script may consume | |||
; https://php.net/memory-limit | |||
memory_limit = -1 | |||
max_memory_limit = -1 | |||
[...] | |||
; Maximum size of POST data that PHP will accept. | |||
; Its value may be 0 to disable the limit. It is ignored if POST data reading | |||
; is disabled through enable_post_data_reading. | |||
; https://php.net/post-max-size | |||
post_max_size = 100M | |||
[...] | |||
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's | |||
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok | |||
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting | |||
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting | |||
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts | |||
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. | |||
; https://php.net/cgi.fix-pathinfo | |||
cgi.fix_pathinfo=0 | |||
[...] | |||
; Whether to allow HTTP file uploads. | |||
; https://php.net/file-uploads | |||
file_uploads = On | |||
[...] | |||
; Maximum allowed size for uploaded files. | |||
; https://php.net/upload-max-filesize | |||
upload_max_filesize = 100M | |||
[...] | |||
; Maximum number of files that can be uploaded via a single request | |||
max_file_uploads = 20 | |||
[...] | |||
[Session] | |||
; Handler used to store/retrieve data. | |||
; https://php.net/session.save-handler | |||
session.save_handler = files | |||
[...] | |||
</syntaxhighlight> | |||
* Reiniciar php-fpm: | |||
<syntaxhighlight lang="Bash">systemctl restart php8.5-fpm.service</syntaxhighlight> | |||
== Configuración Nginx == | |||
* Backup nginx.conf | |||
<syntaxhighlight lang="Bash">cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y%m%d)</syntaxhighlight> | |||
* Editar nginx.conf | |||
<syntaxhighlight lang="Bash">vi /etc/nginx/nginx.conf</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
[...] | |||
http { | |||
## | |||
# Basic Settings | |||
## | |||
sendfile on; | |||
tcp_nopush on; | |||
types_hash_max_size 2048; | |||
client_max_body_size 100M; | |||
server_tokens off; | |||
[...] | |||
## | |||
# SSL Settings | |||
## | |||
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE | |||
ssl_protocols TLSv1.2 TLSv1.3; | |||
ssl_prefer_server_ciphers on; | |||
ssl_dhparam /etc/nginx/ssl/dhparam.pem; | |||
[...] | |||
} | |||
</syntaxhighlight> | |||
* Generar PHParam: | |||
<syntaxhighlight lang="Bash">mkdir /etc/nginx/ssl</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096</syntaxhighlight> | |||
* Configurar contraseñas: | |||
Si se quiere configurar contraseñas Auth Basic se almacenan en /etc/nginx/passwd. | |||
<syntaxhighlight lang="Bash">mkdir /etc/nginx/passwd</syntaxhighlight> | |||
Por ejemplo: | |||
<syntaxhighlight lang="Bash">htpasswd -c -B /etc/nginx/passwd/test.pw guzman</syntaxhighlight> | |||
* Configurar snippets: | |||
Estos "fragmentos" se pueden usar para permitir que sistemas funcionen si se tiene Auth Basic activo (como robots.txt o validación de Let's Encrypt). | |||
<syntaxhighlight lang="Bash">vi /etc/nginx/snippets/allowed.conf</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
# Allow favicon.ico, robots.txt, .well-known/ | |||
location = /favicon.ico { | |||
log_not_found off; | |||
access_log off; | |||
} | |||
# Allow robots.txt | |||
location = /robots.txt { | |||
allow all; | |||
log_not_found off; | |||
access_log off; | |||
} | |||
# Allow "Well-Known URIs" as pwe RFC 5785 (e.g. Let's Encrypt) | |||
location ~* ^/.well-known/ { | |||
auth_basic off; | |||
allow all; | |||
} | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">vi /etc/nginx/snippets/denied.conf</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
# Deny *.txt, *.log, .*/*.php, .*, *.json, .lock, *.ht | |||
# Not allow txt or logs to be downloaded | |||
location ~* \.(txt|log)$ { | |||
deny all; | |||
} | |||
# Not allow execute php in hidden folders | |||
location ~ \..*/.\.php$ { | |||
return 403; | |||
} | |||
# Not allow "hidden files" | |||
location ~ (^|/)\. { | |||
return 403; | |||
} | |||
# Not allow *.json or *.lock | |||
location ~* \.(json|lock)$ { | |||
return 403; | |||
} | |||
# Deny *.ht | |||
location ~ /\.ht { | |||
deny all; | |||
} | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">vi /etc/nginx/snippets/hsts.conf</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
# Activate HSTS (HTTP Strict Transport Security) | |||
# Note: if we set another header in a location we've to | |||
# rewrite it | |||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; | |||
</syntaxhighlight> | |||
* Configurar sites-available: | |||
En al carpeta /etc/nginx/sites-available/ se almacenan todos los Virtual Hosts disponibles. | |||
En Nginx hay que personalizar cada uno por cada tipo de aplicación. | |||
Hay que tener en cuenta las diferentes URL's. | |||
* Configurar sites-enabled: | |||
Se suelen configurar enlaces simbólicos con la carpeta sites-available para activarlos. | |||
Por ejemplo: | |||
<syntaxhighlight lang="Bash">ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default</syntaxhighlight> | |||
* Reiniciar Nginx: | |||
<syntaxhighlight lang="Bash">systemctl restart nginx</syntaxhighlight> | |||
== Configuración MariaDB == | |||
* Conectar a MariaDB | |||
<syntaxhighlight lang="Bash">mariadb</syntaxhighlight> | |||
* Opción 1: Permitir conexiones por TCP (sólo desde localhost) | |||
<syntaxhighlight lang="Sql"> | |||
grant all privileges on *.* to 'root'@'localhost' identified by 'password' with grant option; | |||
FLUSH PRIVILEGES; | |||
</syntaxhighlight> | |||
* Opción 2: Permitir conexiones por Sockets UNIX (sólo desde localhost) | |||
<syntaxhighlight lang="Sql"> | |||
grant all privileges on *.* to 'root'@'localhost' identified via unix_socket with grant option; | |||
FLUSH PRIVILEGES; | |||
</syntaxhighlight> | |||
Nota: esta opción es la que suelo usar yo (no se pueden usar los dos a la vez). | |||
== Habilitar puertos en cortafuegos == | |||
<syntaxhighlight lang="Bash">ufw allow 80/tcp</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">ufw allow 443/tcp</syntaxhighlight> | |||
== Virtual Host de ejemplo == | |||
=== Generar certificados autofirmados (temporales) === | |||
Estos certificados los vamos a generar sólo para levantar el Virtual Host y los sustituiremos por unos de Let's Encrypt. | |||
* Generamos clave privada: | |||
<syntaxhighlight lang="Bash">cd /etc/ssl/private</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">openssl genrsa -out selfsigned.key</syntaxhighlight> | |||
* Generamos petición de firma (CSR): | |||
<syntaxhighlight lang="Bash"> | |||
openssl req -key selfsigned.key -new -out selfsigned.csr | |||
You are about to be asked to enter information that will be incorporated | |||
into your certificate request. | |||
What you are about to enter is what is called a Distinguished Name or a DN. | |||
There are quite a few fields but you can leave some blank | |||
For some fields there will be a default value, | |||
If you enter '.', the field will be left blank. | |||
----- | |||
Country Name (2 letter code) [AU]:ES | |||
State or Province Name (full name) [Some-State]:Madrid | |||
Locality Name (eg, city) []:Madrid | |||
Organization Name (eg, company) [Internet Widgits Pty Ltd]:GCV | |||
Organizational Unit Name (eg, section) []:GCV | |||
Common Name (e.g. server FQDN or YOUR name) []:www.culturetas.net | |||
Email Address []: | |||
Please enter the following 'extra' attributes | |||
to be sent with your certificate request | |||
A challenge password []: | |||
An optional company name []: | |||
</syntaxhighlight> | |||
* Auto-firmamos con la misma firma: | |||
<syntaxhighlight lang="Bash">openssl x509 -signkey selfsigned.key -in selfsigned.csr -req -days 365 -out selfsigned.crt</syntaxhighlight> | |||
* Movemos certificados a las carpetas correctas: | |||
<syntaxhighlight lang="Bash">mv selfsigned.key /etc/ssl/private/</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">mv selfsigned.crt /etc/ssl/certs/</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">rm selfsigned.csr</syntaxhighlight> | |||
* Referencia: [https://www.baeldung.com/openssl-self-signed-cert https://www.baeldung.com/openssl-self-signed-cert] | |||
=== Dar de alta Virtual Host en Nginx === | |||
<syntaxhighlight lang="Bash">vi /etc/nginx/sites-available/culturetas.net</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
## | |||
# You should look at the following URL's in order to grasp a solid understanding | |||
# of Nginx configuration files in order to fully unleash the power of Nginx. | |||
# http://wiki.nginx.org/Pitfalls | |||
# http://wiki.nginx.org/QuickStart | |||
# http://wiki.nginx.org/Configuration | |||
# | |||
# Generally, you will want to move this file somewhere, and start with a clean | |||
# file but keep this around for reference. Or just disable in sites-enabled. | |||
# | |||
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. | |||
## | |||
# Default server configuration | |||
# | |||
server { | |||
# Redirect HTTP to HTTPS | |||
listen 80 default_server; | |||
listen [::]:80 default_server; | |||
server_name www.culturetas.net culturetas.net; | |||
# Redirect HTTP to HTTPS | |||
return 301 https://$host$request_uri; | |||
} | |||
server { | |||
# SSL configuration | |||
# | |||
listen 443 ssl http2 default_server; | |||
listen [::]:443 ssl http2 default_server; | |||
ssl_certificate /etc/ssl/certs/selfsigned.crt; | |||
ssl_certificate_key /etc/ssl/private/selfsigned.key; | |||
# | |||
# Note: You should disable gzip for SSL traffic. | |||
# See: https://bugs.debian.org/773332 | |||
# | |||
# Read up on ssl_ciphers to ensure a secure configuration. | |||
# See: https://bugs.debian.org/765782 | |||
# | |||
# Self signed certs generated by the ssl-cert package | |||
# Don't use them in a production server! | |||
# | |||
# include snippets/snakeoil.conf; | |||
root /var/www/culturetas.net; | |||
# Add index.php to the list if you are using PHP | |||
index index.php index.html index.htm; | |||
server_name www.culturetas.net culturetas.net; | |||
access_log /var/log/nginx/culturetas.net-access.log; | |||
error_log /var/log/nginx/culturetas.net-error.log; | |||
# # Auth Basic (for developing) | |||
# auth_basic "Pagina Restringida"; | |||
# auth_basic_user_file /etc/nginx/passwd/passwd-culturetas.net; | |||
# Activate HSTS (HTTP Strict Transport Security) | |||
# Note: reinclude if in a location a header is set | |||
include snippets/hsts.conf; | |||
# Allow favicon.ico, robots.txt, .well-known/ | |||
# Deny *.txt, *.log, .*/*.php, .*, *.json, .lock, *.ht | |||
include snippets/allowed.conf; | |||
include snippets/denied.conf; | |||
location / { | |||
# First attempt to serve request as file, then | |||
# as directory, then fall back to displaying a 404. | |||
#try_files $uri $uri/ =404; | |||
try_files $uri $uri/ /index.php?$args; | |||
} | |||
# pass the PHP scripts to FastCGI server | |||
# | |||
location ~ \.php$ { | |||
include snippets/fastcgi-php.conf; | |||
# # With php8.5-cgi alone (TCP Ports): | |||
# fastcgi_pass 127.0.0.1:9000; | |||
# With php8.5-fpm (UNIX Socket): | |||
fastcgi_pass unix:/run/php/php8.5-fpm.sock; | |||
} | |||
# Disable hidden files | |||
location ~ /\. { | |||
deny all; | |||
} | |||
} | |||
</syntaxhighlight> | |||
=== Desactivar Virtual Host por defecto === | |||
<syntaxhighlight lang="Bash">rm /etc/nginx/sites-enabled/default</syntaxhighlight> | |||
=== Activar Virtual Host nuevo === | |||
<syntaxhighlight lang="Bash">ln -s /etc/nginx/sites-available/culturetas.net /etc/nginx/sites-enabled/culturetas.net</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">systemctl reload nginx</syntaxhighlight> | |||
=== Generar nuevas claves con Let's Encrypt === | |||
El certbot de Let's Encrypt ya contiene un plugin que gestiona Nginx. | |||
Usándolo no sólo nos generará automáticamente las claves y certificados, si no que lo aplicará en el servidor por nosotros. | |||
Además, también se encargará de la renovación, por lo que desatiende toda esa parte de gestión de certificados. | |||
<syntaxhighlight lang="Bash"> | |||
certbot --nginx | |||
Saving debug log to /var/log/letsencrypt/letsencrypt.log | |||
Enter email address or hit Enter to skip. | |||
(Enter 'c' to cancel): admin@ejemplo.com | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
Please read the Terms of Service at: | |||
https://letsencrypt.org/documents/LE-SA-v1.6-August-18-2025.pdf | |||
You must agree in order to register with the ACME server. Do you agree? | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
(Y)es/(N)o: Y | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
Would you be willing, once your first certificate is successfully issued, to | |||
share your email address with the Electronic Frontier Foundation, a founding | |||
partner of the Let's Encrypt project and the non-profit organization that | |||
develops Certbot? We'd like to send you email about our work encrypting the web, | |||
EFF news, campaigns, and ways to support digital freedom. | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
(Y)es/(N)o: N | |||
Account registered. | |||
Which names would you like to activate HTTPS for? | |||
We recommend selecting either all domains, or all domains in a VirtualHost/server block. | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
1: culturetas.net | |||
2: www.culturetas.net | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
Select the appropriate numbers separated by commas and/or spaces, or leave input | |||
blank to select all options shown (Enter 'c' to cancel): 1,2 | |||
Requesting a certificate for culturetas.net and www.culturetas.net | |||
Successfully received certificate. | |||
Certificate is saved at: /etc/letsencrypt/live/culturetas.net/fullchain.pem | |||
Key is saved at: /etc/letsencrypt/live/culturetas.net/privkey.pem | |||
This certificate expires on 2026-05-25. | |||
These files will be updated when the certificate renews. | |||
Certbot has set up a scheduled task to automatically renew this certificate in the background. | |||
Deploying certificate | |||
Successfully deployed certificate for culturetas.net to /etc/nginx/sites-enabled/culturetas.net | |||
Successfully deployed certificate for www.culturetas.net to /etc/nginx/sites-enabled/culturetas.net | |||
Congratulations! You have successfully enabled HTTPS on https://culturetas.net and https://www.culturetas.net | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
If you like Certbot, please consider supporting our work by: | |||
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate | |||
* Donating to EFF: https://eff.org/donate-le | |||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |||
</syntaxhighlight> | |||
=== Desplegar página de ejemplo === | |||
<syntaxhighlight lang="Bash">mkdir /var/www/culturetas.net</syntaxhighlight> | |||
<syntaxhighlight lang="Bash">vi /var/www/culturetas.net/index.html</syntaxhighlight> | |||
<syntaxhighlight lang="text"> | |||
<!DOCTYPE html> | |||
<html lang="es"> | |||
<head> | |||
<meta charset="UTF-8" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> | |||
<title>Culturetas.net - En construcción</title> | |||
<style> | |||
body { | |||
margin: 0; | |||
padding: 0; | |||
height: 100vh; | |||
font-family: system-ui, -apple-system, sans-serif; | |||
background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); | |||
color: white; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
justify-content: center; | |||
text-align: center; | |||
} | |||
.container { | |||
max-width: 700px; | |||
padding: 20px; | |||
} | |||
h1 { | |||
font-size: 4.5rem; | |||
margin: 0.2em 0; | |||
font-weight: 800; | |||
letter-spacing: -1px; | |||
text-shadow: 0 4px 12px rgba(0,0,0,0.3); | |||
} | |||
.subtitle { | |||
font-size: 1.6rem; | |||
margin: 0.8em 0 1.5em; | |||
opacity: 0.95; | |||
} | |||
.construction { | |||
font-size: 8rem; | |||
margin: 0.3em 0; | |||
animation: bounce 3s infinite; | |||
} | |||
p { | |||
font-size: 1.3rem; | |||
line-height: 1.6; | |||
max-width: 600px; | |||
margin: 1.5em auto; | |||
opacity: 0.9; | |||
} | |||
.soon { | |||
font-size: 2rem; | |||
font-weight: bold; | |||
margin-top: 2rem; | |||
color: #fef08a; | |||
text-shadow: 0 2px 10px rgba(0,0,0,0.4); | |||
} | |||
@keyframes bounce { | |||
0%, 20%, 50%, 80%, 100% { transform: translateY(0); } | |||
40% { transform: translateY(-25px); } | |||
60% { transform: translateY(-12px); } | |||
} | |||
@media (max-width: 600px) { | |||
h1 { font-size: 3.2rem; } | |||
.construction { font-size: 6rem; } | |||
.subtitle { font-size: 1.3rem; } | |||
} | |||
</style> | |||
</head> | |||
<body> | |||
<div class="container"> | |||
<div class="construction">🚧</div> | |||
<h1>Culturetas.net</h1> | |||
<div class="subtitle">Está en construcción</div> | |||
<p>Estamos trabajando para traerte un espacio mucho más bonito, rápido y con mucho más contenido cultural interesante.</p> | |||
<p>¡Vuelve en unos días y te sorprenderás!</p> | |||
<div class="soon">Próximamente... ✨</div> | |||
</div> | |||
</body> | |||
</html> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Categoría:Notas]] | [[Categoría:Notas]] | ||
Revisión actual - 19:48 24 feb 2026
Instalación servidor LEMP
Instalaremos:
- GNU Linux (Ubuntu Server 24.04)
- eNginx 1.24.0 (APT Ubuntu)
- MariaDB 10.8 (Repo oficiales de MariaDB)
- PHP 8.5 (PPA ondrej/php)
Permisos de root
Todos los comandos en esta guía se realizarán como root.
sudo -i
Instalación Nginx (Stable)
- Actualizar repositorio
apt update
- Instalar Nginx
apt install nginx
- Instalación Apache Utils
apt install apache2-utils
Instalación MariaDB
- Instalar requisitos
apt install apt-transport-https curl
- Añadir repositorios MariaDB (oficiales)
mkdir -p /etc/apt/keyrings
curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'
vi /etc/apt/sources.list.d/mariadb.sources
# MariaDB 11.8 repository list - created 2026-02-23 08:31 UTC
# https://mariadb.org/download/
X-Repolib-Name: MariaDB
Types: deb
# deb.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details.
# URIs: https://deb.mariadb.org/11.8/ubuntu
URIs: https://mirror.raiolanetworks.com/mariadb/repo/11.8/ubuntu
Suites: noble
Components: main main/debug
Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp
- Actualizar repositorio
apt update
- Instalación de servidor y cliente
apt install mariadb-client mariadb-server mariadb-plugin-provider-bzip2 mariadb-plugin-provider-lz4 mariadb-plugin-provider-lzma mariadb-plugin-provider-lzo mariadb-plugin-provider-snappy
- Inicializar base de datos
mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.
You already have your root account protected, so you can safely answer 'n'.
Switch to unix_socket authentication [Y/n] n
... skipping.
You already have your root account protected, so you can safely answer 'n'.
Change the root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] y
... Success!
Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] Y
... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] Y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] Y
... Success!
Cleaning up...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!
Instalación PHP
Vamos a usar los repositorios PPA de ondrej/php
- Instalar repositorio PPA
add-apt-repository ppa:ondrej/php
- Actualizar repositorios
apt update
- Instalar PHP 8.5
apt install php8.5 php8.5-apcu php8.5-common php8.5-fpm php8.5-curl php8.5-gd php8.5-mysql php8.5-xml php8.5-xmlrpc php8.5-bz2 php8.5-imap php8.5-intl php8.5-mbstring php8.5-soap php8.5-gnupg php8.5-imagick php8.5-mcrypt php8.5-zip
Instalación Let's Encrypt
Vamos a usar Let's Encrypt para generar las claves y certificados usadas para comunicaciones HTTPS.
- Instalar Snap Core
snap install core
- Refrescar Snap Core
snap refresh core
- Instalar Certbot
snap install --classic certbot
- Crear enlace simbólico
ln -s /snap/bin/certbot /usr/local/bin/certbot
- Comprobar que está activada el timer de renovación
systemctl list-timers | grep certbot
Mon 2026-02-23 11:47:00 UTC 12h - - snap.certbot.renew.timer snap.certbot.renew.service
Configuración PHP
- Configuración php-fpm:
vi /etc/php/8.5/fpm/php.ini
[...]
; Maximum amount of memory a script may consume
; https://php.net/memory-limit
memory_limit = 128M
max_memory_limit = -1
[...]
; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; https://php.net/post-max-size
post_max_size = 100M
[...]
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; https://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=0
[...]
; Whether to allow HTTP file uploads.
; https://php.net/file-uploads
file_uploads = On
[...]
; Maximum allowed size for uploaded files.
; https://php.net/upload-max-filesize
upload_max_filesize = 100M
[...]
; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20
[...]
[Session]
; Handler used to store/retrieve data.
; https://php.net/session.save-handler
session.save_handler = files
[...]
- Configuración php-cli:
vi /etc/php/8.5/cli/php.ini
[...]
; Maximum amount of memory a script may consume
; https://php.net/memory-limit
memory_limit = -1
max_memory_limit = -1
[...]
; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; https://php.net/post-max-size
post_max_size = 100M
[...]
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; https://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=0
[...]
; Whether to allow HTTP file uploads.
; https://php.net/file-uploads
file_uploads = On
[...]
; Maximum allowed size for uploaded files.
; https://php.net/upload-max-filesize
upload_max_filesize = 100M
[...]
; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20
[...]
[Session]
; Handler used to store/retrieve data.
; https://php.net/session.save-handler
session.save_handler = files
[...]
- Reiniciar php-fpm:
systemctl restart php8.5-fpm.service
Configuración Nginx
- Backup nginx.conf
cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y%m%d)
- Editar nginx.conf
vi /etc/nginx/nginx.conf
[...]
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
client_max_body_size 100M;
server_tokens off;
[...]
##
# SSL Settings
##
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
[...]
}
- Generar PHParam:
mkdir /etc/nginx/ssl
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096
- Configurar contraseñas:
Si se quiere configurar contraseñas Auth Basic se almacenan en /etc/nginx/passwd.
mkdir /etc/nginx/passwd
Por ejemplo:
htpasswd -c -B /etc/nginx/passwd/test.pw guzman
- Configurar snippets:
Estos "fragmentos" se pueden usar para permitir que sistemas funcionen si se tiene Auth Basic activo (como robots.txt o validación de Let's Encrypt).
vi /etc/nginx/snippets/allowed.conf
# Allow favicon.ico, robots.txt, .well-known/
location = /favicon.ico {
log_not_found off;
access_log off;
}
# Allow robots.txt
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Allow "Well-Known URIs" as pwe RFC 5785 (e.g. Let's Encrypt)
location ~* ^/.well-known/ {
auth_basic off;
allow all;
}
vi /etc/nginx/snippets/denied.conf
# Deny *.txt, *.log, .*/*.php, .*, *.json, .lock, *.ht
# Not allow txt or logs to be downloaded
location ~* \.(txt|log)$ {
deny all;
}
# Not allow execute php in hidden folders
location ~ \..*/.\.php$ {
return 403;
}
# Not allow "hidden files"
location ~ (^|/)\. {
return 403;
}
# Not allow *.json or *.lock
location ~* \.(json|lock)$ {
return 403;
}
# Deny *.ht
location ~ /\.ht {
deny all;
}
vi /etc/nginx/snippets/hsts.conf
# Activate HSTS (HTTP Strict Transport Security)
# Note: if we set another header in a location we've to
# rewrite it
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
- Configurar sites-available:
En al carpeta /etc/nginx/sites-available/ se almacenan todos los Virtual Hosts disponibles. En Nginx hay que personalizar cada uno por cada tipo de aplicación. Hay que tener en cuenta las diferentes URL's.
- Configurar sites-enabled:
Se suelen configurar enlaces simbólicos con la carpeta sites-available para activarlos. Por ejemplo:
ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
- Reiniciar Nginx:
systemctl restart nginx
Configuración MariaDB
- Conectar a MariaDB
mariadb
- Opción 1: Permitir conexiones por TCP (sólo desde localhost)
grant all privileges on *.* to 'root'@'localhost' identified by 'password' with grant option;
FLUSH PRIVILEGES;
- Opción 2: Permitir conexiones por Sockets UNIX (sólo desde localhost)
grant all privileges on *.* to 'root'@'localhost' identified via unix_socket with grant option;
FLUSH PRIVILEGES;
Nota: esta opción es la que suelo usar yo (no se pueden usar los dos a la vez).
Habilitar puertos en cortafuegos
ufw allow 80/tcp
ufw allow 443/tcp
Virtual Host de ejemplo
Generar certificados autofirmados (temporales)
Estos certificados los vamos a generar sólo para levantar el Virtual Host y los sustituiremos por unos de Let's Encrypt.
- Generamos clave privada:
cd /etc/ssl/private
openssl genrsa -out selfsigned.key
- Generamos petición de firma (CSR):
openssl req -key selfsigned.key -new -out selfsigned.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:ES
State or Province Name (full name) [Some-State]:Madrid
Locality Name (eg, city) []:Madrid
Organization Name (eg, company) [Internet Widgits Pty Ltd]:GCV
Organizational Unit Name (eg, section) []:GCV
Common Name (e.g. server FQDN or YOUR name) []:www.culturetas.net
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
- Auto-firmamos con la misma firma:
openssl x509 -signkey selfsigned.key -in selfsigned.csr -req -days 365 -out selfsigned.crt
- Movemos certificados a las carpetas correctas:
mv selfsigned.key /etc/ssl/private/
mv selfsigned.crt /etc/ssl/certs/
rm selfsigned.csr
Dar de alta Virtual Host en Nginx
vi /etc/nginx/sites-available/culturetas.net
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
server {
# Redirect HTTP to HTTPS
listen 80 default_server;
listen [::]:80 default_server;
server_name www.culturetas.net culturetas.net;
# Redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
# SSL configuration
#
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
ssl_certificate /etc/ssl/certs/selfsigned.crt;
ssl_certificate_key /etc/ssl/private/selfsigned.key;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/culturetas.net;
# Add index.php to the list if you are using PHP
index index.php index.html index.htm;
server_name www.culturetas.net culturetas.net;
access_log /var/log/nginx/culturetas.net-access.log;
error_log /var/log/nginx/culturetas.net-error.log;
# # Auth Basic (for developing)
# auth_basic "Pagina Restringida";
# auth_basic_user_file /etc/nginx/passwd/passwd-culturetas.net;
# Activate HSTS (HTTP Strict Transport Security)
# Note: reinclude if in a location a header is set
include snippets/hsts.conf;
# Allow favicon.ico, robots.txt, .well-known/
# Deny *.txt, *.log, .*/*.php, .*, *.json, .lock, *.ht
include snippets/allowed.conf;
include snippets/denied.conf;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
#try_files $uri $uri/ =404;
try_files $uri $uri/ /index.php?$args;
}
# pass the PHP scripts to FastCGI server
#
location ~ \.php$ {
include snippets/fastcgi-php.conf;
# # With php8.5-cgi alone (TCP Ports):
# fastcgi_pass 127.0.0.1:9000;
# With php8.5-fpm (UNIX Socket):
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
# Disable hidden files
location ~ /\. {
deny all;
}
}
Desactivar Virtual Host por defecto
rm /etc/nginx/sites-enabled/default
Activar Virtual Host nuevo
ln -s /etc/nginx/sites-available/culturetas.net /etc/nginx/sites-enabled/culturetas.net
systemctl reload nginx
Generar nuevas claves con Let's Encrypt
El certbot de Let's Encrypt ya contiene un plugin que gestiona Nginx. Usándolo no sólo nos generará automáticamente las claves y certificados, si no que lo aplicará en el servidor por nosotros. Además, también se encargará de la renovación, por lo que desatiende toda esa parte de gestión de certificados.
certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address or hit Enter to skip.
(Enter 'c' to cancel): admin@ejemplo.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at:
https://letsencrypt.org/documents/LE-SA-v1.6-August-18-2025.pdf
You must agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N
Account registered.
Which names would you like to activate HTTPS for?
We recommend selecting either all domains, or all domains in a VirtualHost/server block.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: culturetas.net
2: www.culturetas.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1,2
Requesting a certificate for culturetas.net and www.culturetas.net
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/culturetas.net/fullchain.pem
Key is saved at: /etc/letsencrypt/live/culturetas.net/privkey.pem
This certificate expires on 2026-05-25.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for culturetas.net to /etc/nginx/sites-enabled/culturetas.net
Successfully deployed certificate for www.culturetas.net to /etc/nginx/sites-enabled/culturetas.net
Congratulations! You have successfully enabled HTTPS on https://culturetas.net and https://www.culturetas.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Desplegar página de ejemplo
mkdir /var/www/culturetas.net
vi /var/www/culturetas.net/index.html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Culturetas.net - En construcción</title>
<style>
body {
margin: 0;
padding: 0;
height: 100vh;
font-family: system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%);
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.container {
max-width: 700px;
padding: 20px;
}
h1 {
font-size: 4.5rem;
margin: 0.2em 0;
font-weight: 800;
letter-spacing: -1px;
text-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.subtitle {
font-size: 1.6rem;
margin: 0.8em 0 1.5em;
opacity: 0.95;
}
.construction {
font-size: 8rem;
margin: 0.3em 0;
animation: bounce 3s infinite;
}
p {
font-size: 1.3rem;
line-height: 1.6;
max-width: 600px;
margin: 1.5em auto;
opacity: 0.9;
}
.soon {
font-size: 2rem;
font-weight: bold;
margin-top: 2rem;
color: #fef08a;
text-shadow: 0 2px 10px rgba(0,0,0,0.4);
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-25px); }
60% { transform: translateY(-12px); }
}
@media (max-width: 600px) {
h1 { font-size: 3.2rem; }
.construction { font-size: 6rem; }
.subtitle { font-size: 1.3rem; }
}
</style>
</head>
<body>
<div class="container">
<div class="construction">🚧</div>
<h1>Culturetas.net</h1>
<div class="subtitle">Está en construcción</div>
<p>Estamos trabajando para traerte un espacio mucho más bonito, rápido y con mucho más contenido cultural interesante.</p>
<p>¡Vuelve en unos días y te sorprenderás!</p>
<div class="soon">Próximamente... ✨</div>
</div>
</body>
</html>