diff --git a/content/webdav-nginx.md b/content/webdav-nginx.md new file mode 100644 index 0000000..0ac6ede --- /dev/null +++ b/content/webdav-nginx.md @@ -0,0 +1,358 @@ +Title: WebDAV with nginx +Date: 2016-03-26 +Category: Tutorial + +This website has been hosted on an [Online.net](https://www.online.net) dedicated server since its creation. I've been one of their customers for the past 3 year now, and I still don't have anything bad to say about them. + +They recently upgraded their personnal range, and I took the opportunity to upgrade from a single server running all of my services to 2 servers running LXC containers that are hosting my services. + +It took me 2 days to migrate everything, but it was worth it. If I decide to switch servers again, I'll have to migrate the containers instead of the services themselves. Considering they are stored on a separate BTRFS volume, it shouldn't take me more than a few hours at most. + +During the migration, I realized that I needed to make files that were hosted on one server accessible to the other. I could have gone with CIFS or NFS, but I wanted to have encryption built-in instead of having to rely on a VPN for that. Since I figured it was a good opportunity to learn something new, I ended up going with WebDAV. + +In this tutorial, I'll explain how I've configured a read-only WebDAV share using [nginx](https://www.nginx.com/) and [Let'sEncrypt](https://letsencrypt.org/) SSL certificates between two Debian Jessie containers. + +## Server configuration + +### Installing the required packages + +First thing first, we need to install the packages we'll need for this configuration : + +```bash +apt update + +apt -t jessie-backports install nginx letsencrypt +apt install apache2-utils +``` + +### Getting our first certificate from letsencrypt + +#### letsencrypt configuration + +Let's create a configuration file for letsencrypt : + +```bash +mkdir /etc/letsencrypt + +echo 'rsa-key-size = 3072 +renew-by-default +text = True +agree-tos = True +renew-by-default = True +authenticator = webroot +email = admin@example.com +webroot-path = /var/www/letsencrypt/' > /etc/letsencrypt/cli.ini +``` + +*Please do modify admin@example.com by your actual e-mail address.* + +We also need to create the directory structure where letsencrypt ACME challenge temporary files will be stored : + +``` +mkdir -p /var/www/letsencrypt/.well-known +``` + +#### nginx configuration + +We now need to configure nginx by adding the following in the `/etc/nginx/sites-available/default` file, anywhere in the `server{}` block that is configured to listen on port 80. + +``` +location /.well-known/acme-challenge { + root /var/www/letsencrypt; +} +``` + +Let's make sure that we haven't done anything wrong : + +```bash +nginx -t +``` + +The command should give you the following output : + +``` +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful +``` + +If that's the case, you can safely reload the nginx daemon : + +``` +nginx -s reload +``` + +#### Certificate request + +Now that letsencrypt and nginx are properly configured, we can request our certificate from letsencrypt : + +```bash +letsencrypt --config /etc/letsencrypt/cli.ini certonly -w /var/www/letsencrypt -d www.example.com +``` + +*Please do modify www.example.com by your server's FQDN, and please note that the letsencrypt servers need to be able to resolve that name to your server's IP.* + +If everything goes well, your certificates will be generated and stored in the /etc/letsencrypt folder. + +### WebDAV configuration + +Now that we've obtained our certificate from letsencrypt, we can begin configuring nginx. + +First, we need to comment two SSL directives from the default nginx configuration : + +``` +sed -i '/ssl_/ s/^/#/' /etc/nginx/nginx.conf +``` + +Let's now create a `/etc/nginx/conf.d/ssl.conf` with the following content : + +``` +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:50m; +ssl_session_tickets off; + +ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; +ssl_trusted_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; + +ssl_dhparam /etc/nginx/ssl/dhparam.pem; + +ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; +ssl_prefer_server_ciphers on; + +add_header Strict-Transport-Security max-age=15768000; +add_header X-Frame-Options DENY; +add_header X-Content-Type-Options nosniff; + +ssl_stapling on; +ssl_stapling_verify on; +resolver 127.0.0.1 valid=300s; +resolver_timeout 5s; +``` + +*This configuration will work if you're using a single certificate on your server. If not, you'll have to remove the `ssl_certificate`, `ssl_certificate_key` and `ssl_trusted_certificate` directives from this file and move them to the correct `server{}` block.* + +We now need to generate a `dhparam.pem` file : + +```bash +mkdir /etc/nginx/ssl && chmod 700 /etc/nginx/ssl +openssl dhparam -out /etc/nginx/ssl/dhparam.pem 3072 +chmod 600 /etc/nginx/ssl/dhparam.pem +``` + +Let's now generate a HTTP basic authentication file. This example creates a user named example : + +``` +mkdir /etc/nginx/auth + +htpasswd -c /etc/nginx/auth/webdav example +New password: +Re-type new password: +Adding password for user user +``` + +This file has to be readable by the user running your webserver. For security reasons, we'll make it readable only by him : + +``` +chown -R www-data:nogroup /etc/nginx/auth +chmod 700 /etc/nginx/auth +chmod 400 /etc/nginx/auth/webdav +``` + +Let's now modify our `/etc/nginx/sites-available/default` file with the following content : + +``` +server { + listen 80 default_server; + listen [::]:80 default_server ipv6only=on; + server_name ""; + + return 444; +} + +server { + listen 443 default_server ssl http2; + listen [::]:443 default_server ipv6only=on ssl http2; + server_name ""; + + return 444; +} +``` + +We now have to create a `/etc/nginx/sites-available/example` file that will contain our actual webdav configuration. This example makes a `data` folder stored in `/var/www/` accessible. + +``` +server { + listen 80; + listen [::]:80; + server_name www.example.com; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name www.example.com; + + root /var/www; + + location / { + index index.html; + } + + location /.well-known/acme-challenge { + root /var/www/letsencrypt; + } + + location /data { + client_body_temp_path /tmp; + dav_methods PUT DELETE MKCOL COPY MOVE; + dav_ext_methods PROPFIND OPTIONS; + create_full_put_path on; + dav_access user:r group:r; + + auth_basic "Restricted access"; + auth_basic_user_file auth/webdav; + + limit_except GET { + allow ; + deny all; + } + } + +} +``` + +The last thing we have to do is to create a symlink so that nginx will load our configuration : + +``` +ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example +``` + +Like before, let's make sure our configuration is correct and then reload the daemon : + +``` +nginx -t +nginx -s reload +``` + +That's it for the WebDAV configuration server-side ! + +### nginx monitoring + +If you're using monit, you can easily monitor the nginx daemon by copying the following in `/etc/monit/conf.d/nginx` : + +``` +check process nginx + with pidfile "/run/nginx.pid" + start program = "/bin/systemctl start nginx" + stop program = "/bin/systemctl stop nginx" + alert monit@example.com +``` + +### Certificates auto-renewal + +This goes beyond the scope of the article, but since letsencrypt certficates are only valid for 3 months, you'll need to renew them regularily. You can do so manually or you can setup a cron that does it for you. + +I personnaly use the following script : + +``` +#!/bin/bash + +PRG="/usr/bin/letsencrypt" +CONFIG="/etc/letsencrypt/cli.ini" +MAILDEST="admin@example.com" +GLOBAL=0 + +# www.example.com +$PRG --config $CONFIG certonly -w /var/www/letsencrypt -d www.example.com +[[ $? != 0 ]] && GLOBAL=$(( $GLOBAL + 1 )) + +if [[ $GLOBAL == 0 ]]; then + /usr/sbin/nginx -s reload +else + echo "Something went wrong while renewing the certificates on $(hostname -f) + Manual action needed." | mail -s "Letsencrypt error on $(hostname -f)" $MAILDEST +fi +``` + +You can add multiple domains in the script. As long as you add all 3 lines for each domain, it will not automatically reload nginx if one or more certificate could not be renewed and will send an e-mail to the address configured in the `MAILDEST` variable. + +You can configure this script in the root user crontab using the `crontab -e` command : + +``` +## LETSENCRYPT CERTIFICATE AUTORENEWAL +30 03 01 */2 * /root/bin/tlsrenew +``` +This will run the script every two months, on the first day of the month, at 3:30 AM. + +## Client configuration + +### Installing the required packages + +A single package is required to mount a webdav volume on Debian : + +``` +apt update && apt install davfs2 +``` + +### Mounting the share manually + +If like me, you want to mount your webdav share in a LXC container, you'll first need to make sure that the following line is present in its configuration file : + +``` +lxc.cgroup.devices.allow = c 10:229 rwm +``` + +You'll also need to create the `/dev/fuse` node in the container : + +``` +mknod /dev/fuse c 10 229 +``` + +In any case, we have to edit the `/etc/davfs2/secrets` file to add the mount point, username and password that will be used to mount the share : + +``` +echo '/data webdav notanactualpassword' >> /etc/davfs2/secrets +``` + +Once that's done, we can mount our share with the following command : + +``` +mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root +``` + +You might need to edit the parameters depending on which users you want to make the share available to. + +### Mouting the share on boot + +A davfs volume can be mounted via the `/etc/fstab` file, but I decided to use monit instead so that the volume would be mounted again automatically should my WebDAV server reboot. + +In order to do so, I first created a `davfs.txt` file in the `/var/www/data` folder on my WebDAV server : + +``` +touch /var/www/data/davfs.txt +``` + +I then created the following `/root/bin/mount_davfs` script : + +``` +#!/bin/bash + +mknod /dev/fuse c 10 229 +mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root +``` + +The last thing I did was create a `/etc/monit/conf.d/davfs` file with the following content : + +``` +check file davfs with path /data/davfs.txt + alert monit@example.com + if does not exist then exec "/root/bin/mount_davfs" +``` + +That way, if monit notices that the `/data/davfs.txt` file becomes inaccessible for some reason, it will try remouting the share. + +## Conclusion + +That's all ! Hopefully this has been useful to someone. Please do comment below if you have any question or if this has been helpful ! \ No newline at end of file diff --git a/output/archives.html b/output/archives.html index 5eae02e..724e230 100644 --- a/output/archives.html +++ b/output/archives.html @@ -88,6 +88,8 @@
+
Sat 26 March 2016
+
WebDAV with nginx
Sun 13 March 2016
MySQL backup script
Sun 06 March 2016
diff --git a/output/author/antoine-joubert.html b/output/author/antoine-joubert.html index 885e6ff..265e1ff 100644 --- a/output/author/antoine-joubert.html +++ b/output/author/antoine-joubert.html @@ -87,6 +87,18 @@
+
+ +

+ WebDAV with nginx +

+
+

This website has been hosted on an Online.net dedicated server since its creation. I've been one ... +

+

There are comments.

diff --git a/output/authors.html b/output/authors.html index 91fc8ea..891f3bd 100644 --- a/output/authors.html +++ b/output/authors.html @@ -90,7 +90,7 @@

- Antoine Joubert (7) + Antoine Joubert (8)

diff --git a/output/category/tutorial.html b/output/category/tutorial.html index 79f15ba..e4765ba 100644 --- a/output/category/tutorial.html +++ b/output/category/tutorial.html @@ -87,6 +87,18 @@
+
+ +

+ WebDAV with nginx +

+
+

This website has been hosted on an Online.net dedicated server since its creation. I've been one ... +

+

There are comments.

diff --git a/output/index.html b/output/index.html index 37ed9b4..cd58429 100644 --- a/output/index.html +++ b/output/index.html @@ -90,6 +90,18 @@
+
+ +

+ WebDAV with nginx +

+
+

This website has been hosted on an Online.net dedicated server since its creation. I've been one ... +

+

There are comments.

diff --git a/output/rss.xml b/output/rss.xml index 3cf6aaf..52b7e06 100644 --- a/output/rss.xml +++ b/output/rss.xml @@ -1,5 +1,319 @@ -Sysadmining. All day. Every day.https://captainark.net/2016-03-13T00:00:00+01:00MySQL backup script2016-03-13T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-03-13:mysql-backup-script.html<p>I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but hey, I figured I'd share it here anyway.</p> +Sysadmining. All day. Every day.https://captainark.net/2016-03-26T00:00:00+01:00WebDAV with nginx2016-03-26T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-03-26:webdav-with-nginx.html<p>This website has been hosted on an <a href="https://www.online.net">Online.net</a> dedicated server since its creation. I've been one of their customers for the past 3 year now, and I still don't have anything bad to say about them.</p> +<p>They recently upgraded their personnal range, and I took the opportunity to upgrade from a single server running all of my services to 2 servers running LXC containers that are hosting my services.</p> +<p>It took me 2 days to migrate everything, but it was worth it. If I decide to switch servers again, I'll have to migrate the containers instead of the services themselves. Considering they are stored on a separate BTRFS volume, it shouldn't take me more than a few hours at most.</p> +<p>During the migration, I realized that I needed to make files that were hosted on one server accessible to the other. I could have gone with CIFS or NFS, but I wanted to have encryption built-in instead of having to rely on a VPN for that. Since I figured it was a good opportunity to learn something new, I ended up going with WebDAV.</p> +<p>In this tutorial, I'll explain how I've configured a read-only WebDAV share using <a href="https://www.nginx.com/">nginx</a> and <a href="https://letsencrypt.org/">Let'sEncrypt</a> SSL certificates between two Debian Jessie containers.</p> +<h2>Server configuration</h2> +<h3>Installing the required packages</h3> +<p>First thing first, we need to install the packages we'll need for this configuration :</p> +<div class="highlight"><pre><span></span>apt update + +apt -t jessie-backports install nginx letsencrypt +apt install apache2-utils +</pre></div> + + +<h3>Getting our first certificate from letsencrypt</h3> +<h4>letsencrypt configuration</h4> +<p>Let's create a configuration file for letsencrypt :</p> +<div class="highlight"><pre><span></span>mkdir /etc/letsencrypt + +<span class="nb">echo</span> <span class="s1">&#39;rsa-key-size = 3072</span> +<span class="s1">renew-by-default</span> +<span class="s1">text = True</span> +<span class="s1">agree-tos = True</span> +<span class="s1">renew-by-default = True</span> +<span class="s1">authenticator = webroot</span> +<span class="s1">email = admin@example.com</span> +<span class="s1">webroot-path = /var/www/letsencrypt/&#39;</span> &gt; /etc/letsencrypt/cli.ini +</pre></div> + + +<p><em>Please do modify admin@example.com by your actual e-mail address.</em></p> +<p>We also need to create the directory structure where letsencrypt ACME challenge temporary files will be stored :</p> +<div class="highlight"><pre><span></span>mkdir -p /var/www/letsencrypt/.well-known +</pre></div> + + +<h4>nginx configuration</h4> +<p>We now need to configure nginx by adding the following in the <code>/etc/nginx/sites-available/default</code> file, anywhere in the <code>server{}</code> block that is configured to listen on port 80.</p> +<div class="highlight"><pre><span></span>location /.well-known/acme-challenge { + root /var/www/letsencrypt; +} +</pre></div> + + +<p>Let's make sure that we haven't done anything wrong :</p> +<div class="highlight"><pre><span></span>nginx -t +</pre></div> + + +<p>The command should give you the following output :</p> +<div class="highlight"><pre><span></span><span class="n">nginx</span><span class="o">:</span> <span class="n">the</span> <span class="n">configuration</span> <span class="n">file</span> <span class="sr">/etc/nginx/</span><span class="n">nginx</span><span class="o">.</span><span class="na">conf</span> <span class="n">syntax</span> <span class="k">is</span> <span class="n">ok</span> +<span class="n">nginx</span><span class="o">:</span> <span class="n">configuration</span> <span class="n">file</span> <span class="sr">/etc/nginx/</span><span class="n">nginx</span><span class="o">.</span><span class="na">conf</span> <span class="n">test</span> <span class="k">is</span> <span class="n">successful</span> +</pre></div> + + +<p>If that's the case, you can safely reload the nginx daemon :</p> +<div class="highlight"><pre><span></span>nginx -s reload +</pre></div> + + +<h4>Certificate request</h4> +<p>Now that letsencrypt and nginx are properly configured, we can request our certificate from letsencrypt :</p> +<div class="highlight"><pre><span></span>letsencrypt --config /etc/letsencrypt/cli.ini certonly -w /var/www/letsencrypt -d www.example.com +</pre></div> + + +<p><em>Please do modify www.example.com by your server's FQDN, and please note that the letsencrypt servers need to be able to resolve that name to your server's IP.</em></p> +<p>If everything goes well, your certificates will be generated and stored in the /etc/letsencrypt folder.</p> +<h3>WebDAV configuration</h3> +<p>Now that we've obtained our certificate from letsencrypt, we can begin configuring nginx.</p> +<p>First, we need to comment two SSL directives from the default nginx configuration :</p> +<div class="highlight"><pre><span></span>sed -i &#39;/ssl_/ s/^/#/&#39; /etc/nginx/nginx.conf +</pre></div> + + +<p>Let's now create a <code>/etc/nginx/conf.d/ssl.conf</code> with the following content :</p> +<div class="highlight"><pre><span></span><span class="nt">ssl_session_timeout</span> <span class="nt">1d</span><span class="o">;</span> +<span class="nt">ssl_session_cache</span> <span class="nt">shared</span><span class="nd">:SSL:50m</span><span class="o">;</span> +<span class="nt">ssl_session_tickets</span> <span class="nt">off</span><span class="o">;</span> + +<span class="nt">ssl_certificate</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">letsencrypt</span><span class="o">/</span><span class="nt">live</span><span class="o">/</span><span class="nt">www</span><span class="nc">.example.com</span><span class="o">/</span><span class="nt">fullchain</span><span class="nc">.pem</span><span class="o">;</span> +<span class="nt">ssl_certificate_key</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">letsencrypt</span><span class="o">/</span><span class="nt">live</span><span class="o">/</span><span class="nt">www</span><span class="nc">.example.com</span><span class="o">/</span><span class="nt">privkey</span><span class="nc">.pem</span><span class="o">;</span> +<span class="nt">ssl_trusted_certificate</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">letsencrypt</span><span class="o">/</span><span class="nt">live</span><span class="o">/</span><span class="nt">www</span><span class="nc">.example.com</span><span class="o">/</span><span class="nt">fullchain</span><span class="nc">.pem</span><span class="o">;</span> + +<span class="nt">ssl_dhparam</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">nginx</span><span class="o">/</span><span class="nt">ssl</span><span class="o">/</span><span class="nt">dhparam</span><span class="nc">.pem</span><span class="o">;</span> + +<span class="nt">ssl_protocols</span> <span class="nt">TLSv1</span> <span class="nt">TLSv1</span><span class="nc">.1</span> <span class="nt">TLSv1</span><span class="nc">.2</span><span class="o">;</span> +<span class="nt">ssl_ciphers</span> <span class="s1">&#39;ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS&#39;</span><span class="o">;</span> +<span class="nt">ssl_prefer_server_ciphers</span> <span class="nt">on</span><span class="o">;</span> + +<span class="nt">add_header</span> <span class="nt">Strict-Transport-Security</span> <span class="nt">max-age</span><span class="o">=</span><span class="nt">15768000</span><span class="o">;</span> +<span class="nt">add_header</span> <span class="nt">X-Frame-Options</span> <span class="nt">DENY</span><span class="o">;</span> +<span class="nt">add_header</span> <span class="nt">X-Content-Type-Options</span> <span class="nt">nosniff</span><span class="o">;</span> + +<span class="nt">ssl_stapling</span> <span class="nt">on</span><span class="o">;</span> +<span class="nt">ssl_stapling_verify</span> <span class="nt">on</span><span class="o">;</span> +<span class="nt">resolver</span> <span class="nt">127</span><span class="nc">.0.0.1</span> <span class="nt">valid</span><span class="o">=</span><span class="nt">300s</span><span class="o">;</span> +<span class="nt">resolver_timeout</span> <span class="nt">5s</span><span class="o">;</span> +</pre></div> + + +<p><em>This configuration will work if you're using a single certificate on your server. If not, you'll have to remove the <code>ssl_certificate</code>, <code>ssl_certificate_key</code> and <code>ssl_trusted_certificate</code> directives from this file and move them to the correct <code>server{}</code> block.</em></p> +<p>We now need to generate a <code>dhparam.pem</code> file :</p> +<div class="highlight"><pre><span></span>mkdir /etc/nginx/ssl <span class="o">&amp;&amp;</span> chmod <span class="m">700</span> /etc/nginx/ssl +openssl dhparam -out /etc/nginx/ssl/dhparam.pem 3072 +chmod <span class="m">600</span> /etc/nginx/ssl/dhparam.pem +</pre></div> + + +<p>Let's now generate a HTTP basic authentication file. This example creates a user named example :</p> +<div class="highlight"><pre><span></span>mkdir /etc/nginx/auth + +htpasswd -c /etc/nginx/auth/webdav example +New password: +Re-type new password: +Adding password for user user +</pre></div> + + +<p>This file has to be readable by the user running your webserver. For security reasons, we'll make it readable only by him :</p> +<div class="highlight"><pre><span></span>chown -R www-data:nogroup /etc/nginx/auth +chmod 700 /etc/nginx/auth +chmod 400 /etc/nginx/auth/webdav +</pre></div> + + +<p>Let's now modify our <code>/etc/nginx/sites-available/default</code> file with the following content :</p> +<div class="highlight"><pre><span></span>server { + listen 80 default_server; + listen [::]:80 default_server ipv6only=on; + server_name &quot;&quot;; + + return 444; +} + +server { + listen 443 default_server ssl http2; + listen [::]:443 default_server ipv6only=on ssl http2; + server_name &quot;&quot;; + + return 444; +} +</pre></div> + + +<p>We now have to create a <code>/etc/nginx/sites-available/example</code> file that will contain our actual webdav configuration. This example makes a <code>data</code> folder stored in <code>/var/www/</code> accessible.</p> +<div class="highlight"><pre><span></span><span class="nt">server</span> <span class="p">{</span> + <span class="n">listen</span> <span class="m">80</span><span class="p">;</span> + <span class="n">listen</span> <span class="cp">[</span><span class="p">::</span><span class="cp">]</span><span class="o">:</span><span class="m">80</span><span class="p">;</span> + <span class="n">server_name</span> <span class="n">www</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span><span class="p">;</span> + <span class="n">return</span> <span class="m">301</span> <span class="n">https</span><span class="o">://</span><span class="err">$</span><span class="n">server_name</span><span class="err">$</span><span class="n">request_uri</span><span class="p">;</span> +<span class="p">}</span> + +<span class="nt">server</span> <span class="p">{</span> + <span class="n">listen</span> <span class="m">443</span> <span class="n">ssl</span> <span class="n">http2</span><span class="p">;</span> + <span class="n">listen</span> <span class="cp">[</span><span class="p">::</span><span class="cp">]</span><span class="o">:</span><span class="m">443</span> <span class="n">ssl</span> <span class="n">http2</span><span class="p">;</span> + <span class="n">server_name</span> <span class="n">www</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span><span class="p">;</span> + + <span class="n">root</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">www</span><span class="p">;</span> + + <span class="n">location</span> <span class="o">/</span> <span class="err">{</span> + <span class="n">index</span> <span class="n">index</span><span class="o">.</span><span class="n">html</span><span class="p">;</span> + <span class="p">}</span> + + <span class="nt">location</span> <span class="o">/</span><span class="nc">.well-known</span><span class="o">/</span><span class="nt">acme-challenge</span> <span class="p">{</span> + <span class="n">root</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">www</span><span class="o">/</span><span class="n">letsencrypt</span><span class="p">;</span> + <span class="p">}</span> + + <span class="nt">location</span> <span class="o">/</span><span class="nt">data</span> <span class="p">{</span> + <span class="n">client_body_temp_path</span> <span class="o">/</span><span class="n">tmp</span><span class="p">;</span> + <span class="n">dav_methods</span> <span class="n">PUT</span> <span class="n">DELETE</span> <span class="n">MKCOL</span> <span class="n">COPY</span> <span class="n">MOVE</span><span class="p">;</span> + <span class="n">dav_ext_methods</span> <span class="n">PROPFIND</span> <span class="n">OPTIONS</span><span class="p">;</span> + <span class="n">create_full_put_path</span> <span class="n">on</span><span class="p">;</span> + <span class="n">dav_access</span> <span class="n">user</span><span class="o">:</span><span class="n">r</span> <span class="n">group</span><span class="o">:</span><span class="n">r</span><span class="p">;</span> + + <span class="n">auth_basic</span> <span class="s2">&quot;Restricted access&quot;</span><span class="p">;</span> + <span class="n">auth_basic_user_file</span> <span class="n">auth</span><span class="o">/</span><span class="n">webdav</span><span class="p">;</span> + + <span class="n">limit_except</span> <span class="n">GET</span> <span class="err">{</span> + <span class="n">allow</span> <span class="o">&lt;</span><span class="n">YOUR</span> <span class="n">IP</span> <span class="n">HERE</span><span class="o">&gt;</span><span class="p">;</span> + <span class="n">deny</span> <span class="n">all</span><span class="p">;</span> + <span class="p">}</span> + <span class="err">}</span> + +<span class="err">}</span> +</pre></div> + + +<p>The last thing we have to do is to create a symlink so that nginx will load our configuration :</p> +<div class="highlight"><pre><span></span>ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example +</pre></div> + + +<p>Like before, let's make sure our configuration is correct and then reload the daemon :</p> +<div class="highlight"><pre><span></span>nginx -t +nginx -s reload +</pre></div> + + +<p>That's it for the WebDAV configuration server-side !</p> +<h3>nginx monitoring</h3> +<p>If you're using monit, you can easily monitor the nginx daemon by copying the following in <code>/etc/monit/conf.d/nginx</code> :</p> +<div class="highlight"><pre><span></span>check process nginx + with pidfile &quot;/run/nginx.pid&quot; + start program = &quot;/bin/systemctl start nginx&quot; + stop program = &quot;/bin/systemctl stop nginx&quot; + alert monit@example.com +</pre></div> + + +<h3>Certificates auto-renewal</h3> +<p>This goes beyond the scope of the article, but since letsencrypt certficates are only valid for 3 months, you'll need to renew them regularily. You can do so manually or you can setup a cron that does it for you.</p> +<p>I personnaly use the following script :</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span> + +<span class="nv">PRG</span><span class="o">=</span><span class="s2">&quot;/usr/bin/letsencrypt&quot;</span> +<span class="nv">CONFIG</span><span class="o">=</span><span class="s2">&quot;/etc/letsencrypt/cli.ini&quot;</span> +<span class="nv">MAILDEST</span><span class="o">=</span><span class="s2">&quot;admin@example.com&quot;</span> +<span class="nv">GLOBAL</span><span class="o">=</span>0 + +<span class="c1"># www.example.com</span> +<span class="nv">$PRG</span> --config <span class="nv">$CONFIG</span> certonly -w /var/www/letsencrypt -d www.example.com +<span class="o">[[</span> <span class="nv">$?</span> !<span class="o">=</span> <span class="m">0</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> <span class="nv">GLOBAL</span><span class="o">=</span><span class="k">$((</span> <span class="nv">$GLOBAL</span> <span class="o">+</span> <span class="m">1</span> <span class="k">))</span> + +<span class="k">if</span> <span class="o">[[</span> <span class="nv">$GLOBAL</span> <span class="o">==</span> <span class="m">0</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> + /usr/sbin/nginx -s reload +<span class="k">else</span> + <span class="nb">echo</span> <span class="s2">&quot;Something went wrong while renewing the certificates on </span><span class="k">$(</span>hostname -f<span class="k">)</span><span class="s2"></span> +<span class="s2"> Manual action needed.&quot;</span> <span class="p">|</span> mail -s <span class="s2">&quot;Letsencrypt error on </span><span class="k">$(</span>hostname -f<span class="k">)</span><span class="s2">&quot;</span> <span class="nv">$MAILDEST</span> +<span class="k">fi</span> +</pre></div> +</td></tr></table> + +<p>You can add multiple domains in the script. As long as you add all 3 lines for each domain, it will not automatically reload nginx if one or more certificate could not be renewed and will send an e-mail to the address configured in the <code>MAILDEST</code> variable.</p> +<p>You can configure this script in the root user crontab using the <code>crontab -e</code> command :</p> +<div class="highlight"><pre><span></span>## LETSENCRYPT CERTIFICATE AUTORENEWAL +30 03 01 */2 * /root/bin/tlsrenew +</pre></div> + + +<p>This will run the script every two months, on the first day of the month, at 3:30 AM.</p> +<h2>Client configuration</h2> +<h3>Installing the required packages</h3> +<p>A single package is required to mount a webdav volume on Debian :</p> +<div class="highlight"><pre><span></span>apt update &amp;&amp; apt install davfs2 +</pre></div> + + +<h3>Mounting the share manually</h3> +<p>If like me, you want to mount your webdav share in a LXC container, you'll first need to make sure that the following line is present in its configuration file :</p> +<div class="highlight"><pre><span></span>lxc.cgroup.devices.allow = c 10:229 rwm +</pre></div> + + +<p>You'll also need to create the <code>/dev/fuse</code> node in the container :</p> +<div class="highlight"><pre><span></span>mknod /dev/fuse c 10 229 +</pre></div> + + +<p>In any case, we have to edit the <code>/etc/davfs2/secrets</code> file to add the mount point, username and password that will be used to mount the share :</p> +<div class="highlight"><pre><span></span>echo &#39;/data webdav notanactualpassword&#39; &gt;&gt; /etc/davfs2/secrets +</pre></div> + + +<p>Once that's done, we can mount our share with the following command :</p> +<div class="highlight"><pre><span></span>mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root +</pre></div> + + +<p>You might need to edit the parameters depending on which users you want to make the share available to.</p> +<h3>Mouting the share on boot</h3> +<p>A davfs volume can be mounted via the <code>/etc/fstab</code> file, but I decided to use monit instead so that the volume would be mounted again automatically should my WebDAV server reboot.</p> +<p>In order to do so, I first created a <code>davfs.txt</code> file in the <code>/var/www/data</code> folder on my WebDAV server :</p> +<div class="highlight"><pre><span></span>touch /var/www/data/davfs.txt +</pre></div> + + +<p>I then created the following <code>/root/bin/mount_davfs</code> script :</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1 +2 +3 +4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span> + +mknod /dev/fuse c <span class="m">10</span> 229 +mount -t davfs https://www.example.com/data /data -o ro,dir_mode<span class="o">=</span>750,file_mode<span class="o">=</span>640,uid<span class="o">=</span>root,gid<span class="o">=</span>root +</pre></div> +</td></tr></table> + +<p>The last thing I did was create a <code>/etc/monit/conf.d/davfs</code> file with the following content :</p> +<div class="highlight"><pre><span></span>check file davfs with path /data/davfs.txt + alert monit@example.com + if does not exist then exec &quot;/root/bin/mount_davfs&quot; +</pre></div> + + +<p>That way, if monit notices that the <code>/data/davfs.txt</code> file becomes inaccessible for some reason, it will try remouting the share.</p> +<h2>Conclusion</h2> +<p>That's all ! Hopefully this has been useful to someone. Please do comment below if you have any question or if this has been helpful !</p>MySQL backup script2016-03-13T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-03-13:mysql-backup-script.html<p>I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but hey, I figured I'd share it here anyway.</p> <h2>The script</h2> <p>For the script to work, you'll need to edit a few variable to match your configuration.</p> <ul> diff --git a/output/webdav-with-nginx.html b/output/webdav-with-nginx.html new file mode 100644 index 0000000..3df4eb9 --- /dev/null +++ b/output/webdav-with-nginx.html @@ -0,0 +1,550 @@ + + + + + + + + + + + + WebDAV with nginx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+

WebDAV with nginx

+ Posted by + Antoine Joubert + on Sat 26 March 2016 + + +
+
+
+
+
+ + +
+
+
+ +
+

This website has been hosted on an Online.net dedicated server since its creation. I've been one of their customers for the past 3 year now, and I still don't have anything bad to say about them.

+

They recently upgraded their personnal range, and I took the opportunity to upgrade from a single server running all of my services to 2 servers running LXC containers that are hosting my services.

+

It took me 2 days to migrate everything, but it was worth it. If I decide to switch servers again, I'll have to migrate the containers instead of the services themselves. Considering they are stored on a separate BTRFS volume, it shouldn't take me more than a few hours at most.

+

During the migration, I realized that I needed to make files that were hosted on one server accessible to the other. I could have gone with CIFS or NFS, but I wanted to have encryption built-in instead of having to rely on a VPN for that. Since I figured it was a good opportunity to learn something new, I ended up going with WebDAV.

+

In this tutorial, I'll explain how I've configured a read-only WebDAV share using nginx and Let'sEncrypt SSL certificates between two Debian Jessie containers.

+

Server configuration

+

Installing the required packages

+

First thing first, we need to install the packages we'll need for this configuration :

+
apt update
+
+apt -t jessie-backports install nginx letsencrypt
+apt install apache2-utils
+
+ + +

Getting our first certificate from letsencrypt

+

letsencrypt configuration

+

Let's create a configuration file for letsencrypt :

+
mkdir /etc/letsencrypt
+
+echo 'rsa-key-size = 3072
+renew-by-default
+text = True
+agree-tos = True
+renew-by-default = True
+authenticator = webroot
+email = admin@example.com
+webroot-path = /var/www/letsencrypt/' > /etc/letsencrypt/cli.ini
+
+ + +

Please do modify admin@example.com by your actual e-mail address.

+

We also need to create the directory structure where letsencrypt ACME challenge temporary files will be stored :

+
mkdir -p /var/www/letsencrypt/.well-known
+
+ + +

nginx configuration

+

We now need to configure nginx by adding the following in the /etc/nginx/sites-available/default file, anywhere in the server{} block that is configured to listen on port 80.

+
location /.well-known/acme-challenge {
+  root /var/www/letsencrypt;
+}
+
+ + +

Let's make sure that we haven't done anything wrong :

+
nginx -t
+
+ + +

The command should give you the following output :

+
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
+nginx: configuration file /etc/nginx/nginx.conf test is successful
+
+ + +

If that's the case, you can safely reload the nginx daemon :

+
nginx -s reload
+
+ + +

Certificate request

+

Now that letsencrypt and nginx are properly configured, we can request our certificate from letsencrypt :

+
letsencrypt --config /etc/letsencrypt/cli.ini certonly -w /var/www/letsencrypt -d www.example.com
+
+ + +

Please do modify www.example.com by your server's FQDN, and please note that the letsencrypt servers need to be able to resolve that name to your server's IP.

+

If everything goes well, your certificates will be generated and stored in the /etc/letsencrypt folder.

+

WebDAV configuration

+

Now that we've obtained our certificate from letsencrypt, we can begin configuring nginx.

+

First, we need to comment two SSL directives from the default nginx configuration :

+
sed -i '/ssl_/ s/^/#/' /etc/nginx/nginx.conf
+
+ + +

Let's now create a /etc/nginx/conf.d/ssl.conf with the following content :

+
ssl_session_timeout 1d;
+ssl_session_cache shared:SSL:50m;
+ssl_session_tickets off;
+
+ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
+ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
+ssl_trusted_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
+
+ssl_dhparam /etc/nginx/ssl/dhparam.pem;
+
+ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
+ssl_prefer_server_ciphers on;
+
+add_header Strict-Transport-Security max-age=15768000;
+add_header X-Frame-Options DENY;
+add_header X-Content-Type-Options nosniff;
+
+ssl_stapling on;
+ssl_stapling_verify on;
+resolver 127.0.0.1 valid=300s;
+resolver_timeout 5s;
+
+ + +

This configuration will work if you're using a single certificate on your server. If not, you'll have to remove the ssl_certificate, ssl_certificate_key and ssl_trusted_certificate directives from this file and move them to the correct server{} block.

+

We now need to generate a dhparam.pem file :

+
mkdir /etc/nginx/ssl && chmod 700 /etc/nginx/ssl
+openssl dhparam -out /etc/nginx/ssl/dhparam.pem 3072
+chmod 600 /etc/nginx/ssl/dhparam.pem
+
+ + +

Let's now generate a HTTP basic authentication file. This example creates a user named example :

+
mkdir /etc/nginx/auth
+
+htpasswd -c /etc/nginx/auth/webdav example
+New password: 
+Re-type new password: 
+Adding password for user user
+
+ + +

This file has to be readable by the user running your webserver. For security reasons, we'll make it readable only by him :

+
chown -R www-data:nogroup /etc/nginx/auth
+chmod 700 /etc/nginx/auth
+chmod 400 /etc/nginx/auth/webdav
+
+ + +

Let's now modify our /etc/nginx/sites-available/default file with the following content :

+
server {
+  listen 80 default_server;
+  listen [::]:80 default_server ipv6only=on;
+  server_name "";
+
+  return 444;
+}
+
+server {
+  listen 443 default_server ssl http2;
+  listen [::]:443 default_server ipv6only=on ssl http2;
+  server_name "";
+
+  return 444;
+}
+
+ + +

We now have to create a /etc/nginx/sites-available/example file that will contain our actual webdav configuration. This example makes a data folder stored in /var/www/ accessible.

+
server {
+  listen 80;
+  listen [::]:80;
+  server_name www.example.com;
+  return 301 https://$server_name$request_uri;
+}
+
+server {
+  listen 443 ssl http2;
+  listen [::]:443 ssl http2;
+  server_name www.example.com;
+
+  root /var/www;
+
+  location / {
+    index index.html;
+  }
+
+  location /.well-known/acme-challenge {
+    root /var/www/letsencrypt;
+  }
+
+  location /data {
+    client_body_temp_path /tmp;
+    dav_methods PUT DELETE MKCOL COPY MOVE;
+    dav_ext_methods PROPFIND OPTIONS;
+    create_full_put_path on;
+    dav_access user:r group:r;
+
+    auth_basic "Restricted access";
+    auth_basic_user_file auth/webdav;
+
+    limit_except GET {
+      allow <YOUR IP HERE>;
+      deny all;
+    }
+  }
+
+}
+
+ + +

The last thing we have to do is to create a symlink so that nginx will load our configuration :

+
ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example
+
+ + +

Like before, let's make sure our configuration is correct and then reload the daemon :

+
nginx -t
+nginx -s reload
+
+ + +

That's it for the WebDAV configuration server-side !

+

nginx monitoring

+

If you're using monit, you can easily monitor the nginx daemon by copying the following in /etc/monit/conf.d/nginx :

+
check process nginx
+  with pidfile "/run/nginx.pid"
+  start program = "/bin/systemctl start nginx"
+  stop program = "/bin/systemctl stop nginx"
+  alert monit@example.com
+
+ + +

Certificates auto-renewal

+

This goes beyond the scope of the article, but since letsencrypt certficates are only valid for 3 months, you'll need to renew them regularily. You can do so manually or you can setup a cron that does it for you.

+

I personnaly use the following script :

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
#!/bin/bash
+
+PRG="/usr/bin/letsencrypt"
+CONFIG="/etc/letsencrypt/cli.ini"
+MAILDEST="admin@example.com"
+GLOBAL=0
+
+# www.example.com
+$PRG --config $CONFIG certonly -w /var/www/letsencrypt -d www.example.com
+[[ $? != 0 ]] && GLOBAL=$(( $GLOBAL + 1 ))
+
+if [[ $GLOBAL == 0 ]]; then
+  /usr/sbin/nginx -s reload
+else
+  echo "Something went wrong while renewing the certificates on $(hostname -f)
+  Manual action needed." | mail -s "Letsencrypt error on $(hostname -f)" $MAILDEST
+fi
+
+
+ +

You can add multiple domains in the script. As long as you add all 3 lines for each domain, it will not automatically reload nginx if one or more certificate could not be renewed and will send an e-mail to the address configured in the MAILDEST variable.

+

You can configure this script in the root user crontab using the crontab -e command :

+
## LETSENCRYPT CERTIFICATE AUTORENEWAL
+30 03 01 */2 * /root/bin/tlsrenew
+
+ + +

This will run the script every two months, on the first day of the month, at 3:30 AM.

+

Client configuration

+

Installing the required packages

+

A single package is required to mount a webdav volume on Debian :

+
apt update && apt install davfs2
+
+ + +

Mounting the share manually

+

If like me, you want to mount your webdav share in a LXC container, you'll first need to make sure that the following line is present in its configuration file :

+
lxc.cgroup.devices.allow = c 10:229 rwm
+
+ + +

You'll also need to create the /dev/fuse node in the container :

+
mknod /dev/fuse c 10 229
+
+ + +

In any case, we have to edit the /etc/davfs2/secrets file to add the mount point, username and password that will be used to mount the share :

+
echo '/data webdav notanactualpassword' >> /etc/davfs2/secrets
+
+ + +

Once that's done, we can mount our share with the following command :

+
mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root
+
+ + +

You might need to edit the parameters depending on which users you want to make the share available to.

+

Mouting the share on boot

+

A davfs volume can be mounted via the /etc/fstab file, but I decided to use monit instead so that the volume would be mounted again automatically should my WebDAV server reboot.

+

In order to do so, I first created a davfs.txt file in the /var/www/data folder on my WebDAV server :

+
touch /var/www/data/davfs.txt
+
+ + +

I then created the following /root/bin/mount_davfs script :

+
1
+2
+3
+4
#!/bin/bash
+
+mknod /dev/fuse c 10 229
+mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root
+
+
+ +

The last thing I did was create a /etc/monit/conf.d/davfs file with the following content :

+
check file davfs with path /data/davfs.txt
+  alert monit@example.com
+  if does not exist then exec "/root/bin/mount_davfs"
+
+ + +

That way, if monit notices that the /data/davfs.txt file becomes inaccessible for some reason, it will try remouting the share.

+

Conclusion

+

That's all ! Hopefully this has been useful to someone. Please do comment below if you have any question or if this has been helpful !

+
+ + +
+ +
+ +
+

Comments !

+
+ + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file