Cuando en 2014 contraté un Droplet en Digital Ocean, no tuve demasiado en cuenta que no estaba pagando por un VPS administrado y en los problemas que en el futuro esto me supondría.
En su momento fui muy optimista y pensé que me serviría de autoaprendizaje y aunque es cierto que he aprendido mucho gestionándolo, creo que, a día de hoy, preferiría no haberle dedicado tantos esfuerzos. Muchas noches en vela intentando hacer funcionar Ubuntu tras una actualización o tras instalar un módulo PHP que necesitaba para cierto proyecto alojado, me han hecho llegar a esta conclusión.
Y heme aquí, escribiendo un artículo para que la próxima vez que me toque crear una cuenta FTP para alguien, no me cueste horas sino minutos.
Disclaimer: Hay que tener en cuenta, que no soy experto en servidores y que probablemente, todo lo que aquí describo puede no ser exactamente correcto o diferir de lo que pasó realmente en cierta medida, porque lo escribo de memoria. Tal vez si alguien sigue estos pasos no le funcione por diversos motivos. Si es así, podéis escribir un comentario e intentaré ayudaros si os interesa pero tened en cuenta que no soy ningún experto.
Crear una cuenta FTP adicional para subir páginas web
Es curioso que, cuando buscas información acerca de esto en internet, la mayoría de artículos que explican como crear una cuenta FTP en un servidor Apache con Ubuntu instalado, la mayoría van enfocados a crear cuentas que están destinadas a albergar documentos de texto, imágenes, etc. con el objetivo de compartir estos ficheros almacenados con otras personas o para tenerlos disponibles desde distintas ubicaciones, como si de una nube improvisada se tratase.
En cuanto a tutoriales para albergar páginas web hay muy pocos y en gran parte de ellos, o no funciona de ninguna manera lo que explican (no se si por desactualización de los mismos o por algún tema de configuración de mi servidor) o no funcionan exactamente como deberían.
El caso es que necesitaba crear una cuenta FTP que solamente tuviese acceso a una carpeta en concreto y hacer que un dominio apuntase a esa carpeta. Lo primero que se recomienda para estos casos es instalar Vsftpd, que va a ser el servidor FTP que utilicemos para conectarnos a dicha carpeta. Para ello utilizaremos este comando:
$ sudo apt-get install vsftpd
A continuación debemos editar el archivo de configuración de Vsftpd. Yo he utilizado nano, vosotros utilizad el que más os guste:
$ sudo nano /etc/vsftpd.conf
Tenemos que buscar la línea en la que pone:
#write_enable=YES
y descomentar esta opción, quitándole la # de delante.
write_enable=YES
Tras guardar los cambios con ctrl+x
y salir del editor, tendremos que crear un nuevo usuario de Linux, el cual será nuestro nombre de usuario para la cuenta FTP. Lo crearemos con este comando:
$ sudo adduser myusername
Tienes que sustituir “myusername” por el nombre de usuario que desees.
Crear un virtualhost en Apache
La cuenta que hemos creado es para habilitar el acceso a los archivos de una web, por lo que para habilitar el acceso mediante un dominio que tengamos, necesitamos crear un virtualhost que redirija ese dominio a una carpeta concreta.
Para crear este virtualhost utilizaremos:
$ sudo nano /etc/apache2/sites-available/mywebsite.dev.conf
Sustituyendo “mywebsite.dev” por nuestro dominio. Personalmente soy partidario de poner también la extensión del dominio para tener mejor organizados los virtualhost y saber qué archivo es de cada dominio.
En el archivo que acabamos de crear tendremos que poner la siguiente configuración:
<VirtualHost *:80>
ServerAdmin mail@mywebsite.dev
DocumentRoot /var/www/mywebsite.dev
ServerName mywebsite.dev
ServerAlias www.mywebsite.dev
<Directory /var/www/mywebsite.dev>
Options FollowSymLinks Multiviews
AllowOverride All
Order allow,deny
allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Guardamos el archivo con ctrl+x
y a continuación tendremos que habilitar el site con este comando:
$ sudo a2ensite mywebsite.dev.conf
A continuación tendremos que recargar Apache para que reconozca la nueva configuración:
$ sudo systemctl reload apache2
Vamos a hacer un inciso
En este momento vamos a parar un segundo, por lo que si estás siguiendo este artículo como si de un tutorial paso a paso se tratase, te recomiendo que pares. A continuación voy a contar los palos de ciego que di hasta dar con la solución.
Lo que suelen sugerir los tutoriales ahora es que definas la carpeta home del nuevo usuario creado a /var/www
que es la típica carpeta donde se suelen alojar las webs en un servidor Apache. Y la verdad es que tiene todo el sentido del mundo si solamente tienes una web alojada en el servidor.
Pero como no es el caso y hay más proyectos en esa misma ubicación, lo lógico es crear una carpeta dedicada a dicho proyecto y a dicha cuenta, tal como lo configuré antes en el virtualhost, así que creé una carpeta específica dentro de /var/www/
llamada mywebsite.dev
, por lo que quedaría así:
/var/www/mywebsite.dev
A continuación le asigné esta carpeta al usuario como carpeta home con el comando:
$ sudo usermod -d /var/www/mywebsite.dev -m myusername
También añadí al recién creado usuario al grupo del usuario de Apache, www-data:
$ sudo usermod -a -G www-data myusername
Hasta aquí, todo bien. El problema de esto es que si intentaba iniciar sesión en la cuenta, daba error de conexión.
Tras diversas investigaciones llegué a la conclusión de que el problema era debido a permisos del propietario de la carpeta porque si volvía a poner el propietario de la carpeta a “myusername”, funcionaba correctamente, pero si intentaba acceder a la carpeta desde el navegador me daba un error de servidor. Por tanto, necesitaba que el propietario fuese el grupo del usuario de Apache para que se pudiese acceder desde el navegador, pero si lo hacía así, no me dejaba conectarme a la cuenta mediante FTP.
Seguí investigando a ver cual era la mejor solución para conseguir que esto funcionase y llegué a una publicación (que enlazaría aquí pero no guardé en ningún sitio y no la he conseguido encontrar de nuevo) en la que decían que había que poner los propietarios de carpeta de una manera muy especial para que esto funcionase. Concretamente se trataba de dejar la carpeta /var/www/mywebsite.dev
con www-data:www-data
, la carpeta superior /var/www
debía tener root:root
y había que crear una tercera carpeta dentro de /var/www/mywebsite.dev/
que podríamos llamar, por ejemplo, public_html
y ahí darle myusername:myusername
como propietario de la misma.
Claro, esto sería genial si no fuese porque /var/www
necesita tener www-data:www-data
como propietario para que las webs sean accesibles desde el navegador. Por esto mismo, se me ocurrió que tal vez podía sacar la carpeta /var/www/mywebsite.dev
de la estructura /var/www
y ponerla al mismo nivel de www
quedando así:
/var/mywebsite.dev/public_html
Y voilà! De esta manera era accesible desde el navegador y se podía conectar desde la nueva cuenta FTP, pero se me presentaba un problema: el usuario tenía su carpeta como directorio inicial cuando iniciaba sesión, pero también era capaz de acceder a todas las demás carpetas del servidor.
Busqué información para saber como restringir el acceso y llegué a un post que hablaba de que vsftpd te otorga la posibilidad de realizar lo que se llama chroot jail. Para realizar esta restricción de acceso, se necesitan introducir una serie de parámetros en la configuración vsftpd. Así que abrí el archivo vsftpd.conf
y añadí:
chroot_local_user=YES
allow_writeable_chroot=YES
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
A continuación creé el archivo vsftpd.userlist:
$ sudo nano /etc/vsftpd.userlist
Y entonces añadí el nombre de usuario para que solamente pudiese acceder a su propia carpeta, en este caso:
myusername
Después de añadirlos reinicié el servicio vsftpd con:
$ sudo systemctl restart vsftpd
Desgraciadamente, esto no me funcionó. El usuario podía seguir accediendo a otras carpetas después de realizar esta configuración.
Cuando ya estaba a punto de rendirme, encontré un artículo que hablaba de restringir el acceso a la carpeta FTP modificando la configuración de OpenSSH Server. La configuración que necesitaba esto para funcionar es esta:
Match User myusername
PasswordAuthentication yes
ChrootDirectory /var/mywebsite.dev
PermitTunnel no
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
Además de esto, hay que cambiar este parámetro:
Subsystem sftp /usr/lib/openssh/sftp-server
Por este otro:
Subsystem sftp internal-sftp
Después de esto reinicié el servicio SSH con este comando:
$ sudo systemctl restart sshd
Con esta configuración conseguí que el usuario no tuviese acceso a otras carpetas, pero el acceso por web dejó de funcionar, no sé por qué. También probé a volver a mover la carpeta al directorio /var/www
, cambiando la configuración del archivo sshd por consiguiente, pero tampoco llegó a funcionar en ningún momento.
Terminando la configuración
Con todos estos pasos dados y deshaciendo todo lo que tenía que ver con “chroot jail”, tuve claro que la configuración buena era esta última, pero tenía que encontrar alguna manera de hacer funcionar esta configuración pero asignando los permisos correctos a la carpeta final para que Apache tuviese acceso.
Así que teniendo en cuenta esto, recordé que hace unos años, cuando trabajaba con Symfony 2.3 en uno de mis anteriores trabajos, un compañero (gracias Joel), me explicó que había que ejecutar ciertos comandos para que los assets se enlazasen con la vista mediante symlink. Esto me hizo pensar que tal vez sería buena idea hacer lo mismo con los archivos de la web.
Si el acceso por FTP funcionaba con la última configuración de SSH, ¿por qué no hacer un symlink de dicha carpeta con otra en /var/www
donde Apache sí tiene acceso? Pues eso exactamente hice.
Para empezar, como ya no había necesidad de tener la carpeta home del usuario en /var/www
, volví a modificar la ubicación de la misma y la puse en el directorio /home
.
$ sudo usermod -d /home/myusername -m myusername
Creé las siguientes carpetas para que tuviesen la misma estructura en /var/www
y después “clonarlas” con el symlink de marras y les di los siguientes permisos:
$ sudo mkdir /home/myusername/mywebsite.dev
$ sudo mkdir /home/myusername/mywebsite.dev/public_html
$ sudo chown root:root /home/myusername
$ sudo chown root:root /home/myusername/mywebsite.dev
$ sudo chown myusername:myusername -R /home/myusername/mywebsite.dev/public_html
También cambié la configuración del virtualhost inicial para que coincidiese con la nueva estructura:
<VirtualHost *:80>
ServerAdmin mail@mywebsite.dev
DocumentRoot /var/www/mywebsite.dev/public_html
ServerName mywebsite.dev
ServerAlias www.mywebsite.dev
<Directory /var/www/mywebsite.dev/public_html>
Options FollowSymLinks Multiviews
AllowOverride All
Order allow,deny
allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Volví a crear la carpeta correspondiente en /var/www
:
$ sudo mkdir /var/www/mywebsite.dev
Asigné como propietario e usuario al usuario de Apache:
$ sudo chown -R www-data:www-data /var/www/mywebsite.dev
Y le di los siguientes permisos de lectura y escritura:
$ sudo find /var/www/mywebsite.dev -type d -exec chmod 755 {} \;
$ sudo find /var/www/mywebsite.dev -type f -exec chmod 644 {} \;
También cambié esta línea de la configuración SSH:
ChrootDirectory /home/myusername/mywebsite.dev
Y por último hice la conexión entre carpetas con el symlink:
$ ln /home/myusername/mywebsite.dev /var/www/mywebsite.dev
De este modo, el usuario puede subir los archivos que quiera a su carpeta home y estos siempre estarán sincronizados con los archivos de la carpeta web.
Conclusión
Ha quedado un artículo un poco largo. Tal vez la parte del “inciso” sobraba pero me gusta dejarlo reflejado para recordar que nuestros compañeros de sistemas tienen un trabajo muy complicado. Espero que a alguien le sirva.
Tal vez te apetezca dejar un comentario
Los campos marcados con un asterisco (*) son obligatorios.