webdav with nginx #1

This commit is contained in:
CaptainArk 2016-03-26 15:36:09 +01:00
parent 26f00c7265
commit 5ff622f450
8 changed files with 1262 additions and 2 deletions

358
content/webdav-nginx.md Normal file
View File

@ -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 <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 :
```
#!/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 !

View File

@ -88,6 +88,8 @@
<div class="row"> <div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1"> <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<dl> <dl>
<dt>Sat 26 March 2016</dt>
<dd><a href="https://captainark.net/webdav-with-nginx.html">WebDAV with nginx</a></dd>
<dt>Sun 13 March 2016</dt> <dt>Sun 13 March 2016</dt>
<dd><a href="https://captainark.net/mysql-backup-script.html">MySQL backup script</a></dd> <dd><a href="https://captainark.net/mysql-backup-script.html">MySQL backup script</a></dd>
<dt>Sun 06 March 2016</dt> <dt>Sun 06 March 2016</dt>

View File

@ -87,6 +87,18 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1"> <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-preview">
<a href="https://captainark.net/webdav-with-nginx.html" rel="bookmark" title="Permalink to WebDAV with nginx">
<h2 class="post-title">
WebDAV with nginx
</h2>
</a>
<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 ...
<p class="post-meta">Posted by
<a href="https://captainark.net/author/antoine-joubert.html">Antoine Joubert</a>
on Sat 26 March 2016
</p>
<p>There are <a href="https://captainark.net/webdav-with-nginx.html#disqus_thread">comments</a>.</p> </div>
<div class="post-preview"> <div class="post-preview">
<a href="https://captainark.net/mysql-backup-script.html" rel="bookmark" title="Permalink to MySQL backup script"> <a href="https://captainark.net/mysql-backup-script.html" rel="bookmark" title="Permalink to MySQL backup script">
<h2 class="post-title"> <h2 class="post-title">

View File

@ -90,7 +90,7 @@
<div class="post-preview"> <div class="post-preview">
<a href="https://captainark.net/author/antoine-joubert.html" rel="bookmark"> <a href="https://captainark.net/author/antoine-joubert.html" rel="bookmark">
<h2 class="post-title"> <h2 class="post-title">
Antoine Joubert (7) Antoine Joubert (8)
</h2> </h2>
</a> </a>
</div> </div>

View File

@ -87,6 +87,18 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1"> <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-preview">
<a href="https://captainark.net/webdav-with-nginx.html" rel="bookmark" title="Permalink to WebDAV with nginx">
<h2 class="post-title">
WebDAV with nginx
</h2>
</a>
<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 ...
<p class="post-meta">Posted by
<a href="https://captainark.net/author/antoine-joubert.html">Antoine Joubert</a>
on Sat 26 March 2016
</p>
<p>There are <a href="https://captainark.net/webdav-with-nginx.html#disqus_thread">comments</a>.</p> </div>
<div class="post-preview"> <div class="post-preview">
<a href="https://captainark.net/postfix-admin.html" rel="bookmark" title="Permalink to Postfix Admin"> <a href="https://captainark.net/postfix-admin.html" rel="bookmark" title="Permalink to Postfix Admin">
<h2 class="post-title"> <h2 class="post-title">

View File

@ -90,6 +90,18 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1"> <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-preview">
<a href="https://captainark.net/webdav-with-nginx.html" rel="bookmark" title="Permalink to WebDAV with nginx">
<h2 class="post-title">
WebDAV with nginx
</h2>
</a>
<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 ...
<p class="post-meta">Posted by
<a href="https://captainark.net/author/antoine-joubert.html">Antoine Joubert</a>
on Sat 26 March 2016
</p>
<p>There are <a href="https://captainark.net/webdav-with-nginx.html#disqus_thread">comments</a>.</p> </div>
<div class="post-preview"> <div class="post-preview">
<a href="https://captainark.net/mysql-backup-script.html" rel="bookmark" title="Permalink to MySQL backup script"> <a href="https://captainark.net/mysql-backup-script.html" rel="bookmark" title="Permalink to MySQL backup script">
<h2 class="post-title"> <h2 class="post-title">

View File

@ -1,5 +1,319 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Sysadmining. All day. Every day.</title><link href="https://captainark.net/" rel="alternate"></link><link href="https://captainark.net/rss.xml" rel="self"></link><id>https://captainark.net/</id><updated>2016-03-13T00:00:00+01:00</updated><entry><title>MySQL backup script</title><link href="https://captainark.net/mysql-backup-script.html" rel="alternate"></link><updated>2016-03-13T00:00:00+01:00</updated><author><name>Antoine Joubert</name></author><id>tag:captainark.net,2016-03-13:mysql-backup-script.html</id><summary type="html">&lt;p&gt;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.&lt;/p&gt; <feed xmlns="http://www.w3.org/2005/Atom"><title>Sysadmining. All day. Every day.</title><link href="https://captainark.net/" rel="alternate"></link><link href="https://captainark.net/rss.xml" rel="self"></link><id>https://captainark.net/</id><updated>2016-03-26T00:00:00+01:00</updated><entry><title>WebDAV with nginx</title><link href="https://captainark.net/webdav-with-nginx.html" rel="alternate"></link><updated>2016-03-26T00:00:00+01:00</updated><author><name>Antoine Joubert</name></author><id>tag:captainark.net,2016-03-26:webdav-with-nginx.html</id><summary type="html">&lt;p&gt;This website has been hosted on an &lt;a href="https://www.online.net"&gt;Online.net&lt;/a&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;In this tutorial, I'll explain how I've configured a read-only WebDAV share using &lt;a href="https://www.nginx.com/"&gt;nginx&lt;/a&gt; and &lt;a href="https://letsencrypt.org/"&gt;Let'sEncrypt&lt;/a&gt; SSL certificates between two Debian Jessie containers.&lt;/p&gt;
&lt;h2&gt;Server configuration&lt;/h2&gt;
&lt;h3&gt;Installing the required packages&lt;/h3&gt;
&lt;p&gt;First thing first, we need to install the packages we'll need for this configuration :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;apt update
apt -t jessie-backports install nginx letsencrypt
apt install apache2-utils
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Getting our first certificate from letsencrypt&lt;/h3&gt;
&lt;h4&gt;letsencrypt configuration&lt;/h4&gt;
&lt;p&gt;Let's create a configuration file for letsencrypt :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir /etc/letsencrypt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rsa-key-size = 3072&lt;/span&gt;
&lt;span class="s1"&gt;renew-by-default&lt;/span&gt;
&lt;span class="s1"&gt;text = True&lt;/span&gt;
&lt;span class="s1"&gt;agree-tos = True&lt;/span&gt;
&lt;span class="s1"&gt;renew-by-default = True&lt;/span&gt;
&lt;span class="s1"&gt;authenticator = webroot&lt;/span&gt;
&lt;span class="s1"&gt;email = admin@example.com&lt;/span&gt;
&lt;span class="s1"&gt;webroot-path = /var/www/letsencrypt/&amp;#39;&lt;/span&gt; &amp;gt; /etc/letsencrypt/cli.ini
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Please do modify admin@example.com by your actual e-mail address.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We also need to create the directory structure where letsencrypt ACME challenge temporary files will be stored :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir -p /var/www/letsencrypt/.well-known
&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;nginx configuration&lt;/h4&gt;
&lt;p&gt;We now need to configure nginx by adding the following in the &lt;code&gt;/etc/nginx/sites-available/default&lt;/code&gt; file, anywhere in the &lt;code&gt;server{}&lt;/code&gt; block that is configured to listen on port 80.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;location /.well-known/acme-challenge {
root /var/www/letsencrypt;
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's make sure that we haven't done anything wrong :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nginx -t
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The command should give you the following output :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="sr"&gt;/etc/nginx/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;conf&lt;/span&gt; &lt;span class="n"&gt;syntax&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;
&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="sr"&gt;/etc/nginx/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;conf&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;successful&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If that's the case, you can safely reload the nginx daemon :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nginx -s reload
&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Certificate request&lt;/h4&gt;
&lt;p&gt;Now that letsencrypt and nginx are properly configured, we can request our certificate from letsencrypt :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;letsencrypt --config /etc/letsencrypt/cli.ini certonly -w /var/www/letsencrypt -d www.example.com
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;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.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If everything goes well, your certificates will be generated and stored in the /etc/letsencrypt folder.&lt;/p&gt;
&lt;h3&gt;WebDAV configuration&lt;/h3&gt;
&lt;p&gt;Now that we've obtained our certificate from letsencrypt, we can begin configuring nginx.&lt;/p&gt;
&lt;p&gt;First, we need to comment two SSL directives from the default nginx configuration :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sed -i &amp;#39;/ssl_/ s/^/#/&amp;#39; /etc/nginx/nginx.conf
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's now create a &lt;code&gt;/etc/nginx/conf.d/ssl.conf&lt;/code&gt; with the following content :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;ssl_session_timeout&lt;/span&gt; &lt;span class="nt"&gt;1d&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_session_cache&lt;/span&gt; &lt;span class="nt"&gt;shared&lt;/span&gt;&lt;span class="nd"&gt;:SSL:50m&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_session_tickets&lt;/span&gt; &lt;span class="nt"&gt;off&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_certificate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;live&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;www&lt;/span&gt;&lt;span class="nc"&gt;.example.com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;fullchain&lt;/span&gt;&lt;span class="nc"&gt;.pem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;live&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;www&lt;/span&gt;&lt;span class="nc"&gt;.example.com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;privkey&lt;/span&gt;&lt;span class="nc"&gt;.pem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_trusted_certificate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;live&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;www&lt;/span&gt;&lt;span class="nc"&gt;.example.com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;fullchain&lt;/span&gt;&lt;span class="nc"&gt;.pem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_dhparam&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;dhparam&lt;/span&gt;&lt;span class="nc"&gt;.pem&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_protocols&lt;/span&gt; &lt;span class="nt"&gt;TLSv1&lt;/span&gt; &lt;span class="nt"&gt;TLSv1&lt;/span&gt;&lt;span class="nc"&gt;.1&lt;/span&gt; &lt;span class="nt"&gt;TLSv1&lt;/span&gt;&lt;span class="nc"&gt;.2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_ciphers&lt;/span&gt; &lt;span class="s1"&gt;&amp;#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&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;add_header&lt;/span&gt; &lt;span class="nt"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="nt"&gt;max-age&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;15768000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;add_header&lt;/span&gt; &lt;span class="nt"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="nt"&gt;DENY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;add_header&lt;/span&gt; &lt;span class="nt"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="nt"&gt;nosniff&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_stapling&lt;/span&gt; &lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;ssl_stapling_verify&lt;/span&gt; &lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;resolver&lt;/span&gt; &lt;span class="nt"&gt;127&lt;/span&gt;&lt;span class="nc"&gt;.0.0.1&lt;/span&gt; &lt;span class="nt"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;300s&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;resolver_timeout&lt;/span&gt; &lt;span class="nt"&gt;5s&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;This configuration will work if you're using a single certificate on your server. If not, you'll have to remove the &lt;code&gt;ssl_certificate&lt;/code&gt;, &lt;code&gt;ssl_certificate_key&lt;/code&gt; and &lt;code&gt;ssl_trusted_certificate&lt;/code&gt; directives from this file and move them to the correct &lt;code&gt;server{}&lt;/code&gt; block.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We now need to generate a &lt;code&gt;dhparam.pem&lt;/code&gt; file :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir /etc/nginx/ssl &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; chmod &lt;span class="m"&gt;700&lt;/span&gt; /etc/nginx/ssl
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 3072
chmod &lt;span class="m"&gt;600&lt;/span&gt; /etc/nginx/ssl/dhparam.pem
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's now generate a HTTP basic authentication file. This example creates a user named example :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir /etc/nginx/auth
htpasswd -c /etc/nginx/auth/webdav example
New password:
Re-type new password:
Adding password for user user
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This file has to be readable by the user running your webserver. For security reasons, we'll make it readable only by him :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;chown -R www-data:nogroup /etc/nginx/auth
chmod 700 /etc/nginx/auth
chmod 400 /etc/nginx/auth/webdav
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's now modify our &lt;code&gt;/etc/nginx/sites-available/default&lt;/code&gt; file with the following content :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name &amp;quot;&amp;quot;;
return 444;
}
server {
listen 443 default_server ssl http2;
listen [::]:443 default_server ipv6only=on ssl http2;
server_name &amp;quot;&amp;quot;;
return 444;
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now have to create a &lt;code&gt;/etc/nginx/sites-available/example&lt;/code&gt; file that will contain our actual webdav configuration. This example makes a &lt;code&gt;data&lt;/code&gt; folder stored in &lt;code&gt;/var/www/&lt;/code&gt; accessible.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;return&lt;/span&gt; &lt;span class="m"&gt;301&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;://&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;server_name&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt; &lt;span class="n"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;443&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt; &lt;span class="n"&gt;http2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;.well-known&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;acme-challenge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;letsencrypt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;client_body_temp_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dav_methods&lt;/span&gt; &lt;span class="n"&gt;PUT&lt;/span&gt; &lt;span class="n"&gt;DELETE&lt;/span&gt; &lt;span class="n"&gt;MKCOL&lt;/span&gt; &lt;span class="n"&gt;COPY&lt;/span&gt; &lt;span class="n"&gt;MOVE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dav_ext_methods&lt;/span&gt; &lt;span class="n"&gt;PROPFIND&lt;/span&gt; &lt;span class="n"&gt;OPTIONS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;create_full_put_path&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dav_access&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;auth_basic&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Restricted access&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;auth_basic_user_file&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;webdav&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;limit_except&lt;/span&gt; &lt;span class="n"&gt;GET&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;YOUR&lt;/span&gt; &lt;span class="n"&gt;IP&lt;/span&gt; &lt;span class="n"&gt;HERE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;deny&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The last thing we have to do is to create a symlink so that nginx will load our configuration :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Like before, let's make sure our configuration is correct and then reload the daemon :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;nginx -t
nginx -s reload
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it for the WebDAV configuration server-side !&lt;/p&gt;
&lt;h3&gt;nginx monitoring&lt;/h3&gt;
&lt;p&gt;If you're using monit, you can easily monitor the nginx daemon by copying the following in &lt;code&gt;/etc/monit/conf.d/nginx&lt;/code&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;check process nginx
with pidfile &amp;quot;/run/nginx.pid&amp;quot;
start program = &amp;quot;/bin/systemctl start nginx&amp;quot;
stop program = &amp;quot;/bin/systemctl stop nginx&amp;quot;
alert monit@example.com
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Certificates auto-renewal&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;I personnaly use the following script :&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;PRG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/usr/bin/letsencrypt&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/etc/letsencrypt/cli.ini&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;MAILDEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;admin@example.com&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;GLOBAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="c1"&gt;# www.example.com&lt;/span&gt;
&lt;span class="nv"&gt;$PRG&lt;/span&gt; --config &lt;span class="nv"&gt;$CONFIG&lt;/span&gt; certonly -w /var/www/letsencrypt -d www.example.com
&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;GLOBAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="nv"&gt;$GLOBAL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$GLOBAL&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
/usr/sbin/nginx -s reload
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Something went wrong while renewing the certificates on &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname -f&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&lt;/span&gt;
&lt;span class="s2"&gt; Manual action needed.&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; mail -s &lt;span class="s2"&gt;&amp;quot;Letsencrypt error on &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname -f&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;$MAILDEST&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;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 &lt;code&gt;MAILDEST&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;You can configure this script in the root user crontab using the &lt;code&gt;crontab -e&lt;/code&gt; command :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;## LETSENCRYPT CERTIFICATE AUTORENEWAL
30 03 01 */2 * /root/bin/tlsrenew
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will run the script every two months, on the first day of the month, at 3:30 AM.&lt;/p&gt;
&lt;h2&gt;Client configuration&lt;/h2&gt;
&lt;h3&gt;Installing the required packages&lt;/h3&gt;
&lt;p&gt;A single package is required to mount a webdav volume on Debian :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;apt update &amp;amp;&amp;amp; apt install davfs2
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Mounting the share manually&lt;/h3&gt;
&lt;p&gt;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 :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;lxc.cgroup.devices.allow = c 10:229 rwm
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You'll also need to create the &lt;code&gt;/dev/fuse&lt;/code&gt; node in the container :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mknod /dev/fuse c 10 229
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In any case, we have to edit the &lt;code&gt;/etc/davfs2/secrets&lt;/code&gt; file to add the mount point, username and password that will be used to mount the share :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;echo &amp;#39;/data webdav notanactualpassword&amp;#39; &amp;gt;&amp;gt; /etc/davfs2/secrets
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once that's done, we can mount our share with the following command :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You might need to edit the parameters depending on which users you want to make the share available to.&lt;/p&gt;
&lt;h3&gt;Mouting the share on boot&lt;/h3&gt;
&lt;p&gt;A davfs volume can be mounted via the &lt;code&gt;/etc/fstab&lt;/code&gt; file, but I decided to use monit instead so that the volume would be mounted again automatically should my WebDAV server reboot.&lt;/p&gt;
&lt;p&gt;In order to do so, I first created a &lt;code&gt;davfs.txt&lt;/code&gt; file in the &lt;code&gt;/var/www/data&lt;/code&gt; folder on my WebDAV server :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;touch /var/www/data/davfs.txt
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then created the following &lt;code&gt;/root/bin/mount_davfs&lt;/code&gt; script :&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2
3
4&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
mknod /dev/fuse c &lt;span class="m"&gt;10&lt;/span&gt; 229
mount -t davfs https://www.example.com/data /data -o ro,dir_mode&lt;span class="o"&gt;=&lt;/span&gt;750,file_mode&lt;span class="o"&gt;=&lt;/span&gt;640,uid&lt;span class="o"&gt;=&lt;/span&gt;root,gid&lt;span class="o"&gt;=&lt;/span&gt;root
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;The last thing I did was create a &lt;code&gt;/etc/monit/conf.d/davfs&lt;/code&gt; file with the following content :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;check file davfs with path /data/davfs.txt
alert monit@example.com
if does not exist then exec &amp;quot;/root/bin/mount_davfs&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That way, if monit notices that the &lt;code&gt;/data/davfs.txt&lt;/code&gt; file becomes inaccessible for some reason, it will try remouting the share.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;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 !&lt;/p&gt;</summary></entry><entry><title>MySQL backup script</title><link href="https://captainark.net/mysql-backup-script.html" rel="alternate"></link><updated>2016-03-13T00:00:00+01:00</updated><author><name>Antoine Joubert</name></author><id>tag:captainark.net,2016-03-13:mysql-backup-script.html</id><summary type="html">&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;The script&lt;/h2&gt; &lt;h2&gt;The script&lt;/h2&gt;
&lt;p&gt;For the script to work, you'll need to edit a few variable to match your configuration.&lt;/p&gt; &lt;p&gt;For the script to work, you'll need to edit a few variable to match your configuration.&lt;/p&gt;
&lt;ul&gt; &lt;ul&gt;

View File

@ -0,0 +1,550 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Antoine Joubert">
<title>WebDAV with nginx</title>
<link href="https://captainark.net/rss.xml" type="application/atom+xml" rel="alternate" title="Sysadmining. All day. Every day. Full Atom Feed" />
<!-- Bootstrap Core CSS -->
<link href="https://captainark.net/theme/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom CSS -->
<link href="https://captainark.net/theme/css/clean-blog.min.css" rel="stylesheet">
<!-- Code highlight color scheme -->
<link href="https://captainark.net/theme/css/code_blocks/github.css" rel="stylesheet">
<!-- Custom Fonts -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<meta name="description" content="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 ...">
<meta name="author" content="Antoine Joubert">
<meta property="og:locale" content="">
<meta property="og:site_name" content="Sysadmining. All day. Every day.">
<meta property="og:type" content="article">
<meta property="article:author" content="Antoine Joubert" >
<meta property="og:url" content="https://captainark.net/webdav-with-nginx.html">
<meta property="og:title" content="WebDAV with nginx">
<meta property="article:published_time" content="2016-03-26 00:00:00+01:00">
<meta property="og:description" content="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 ...">
<meta property="og:image" content="https://captainark.net//bg.png">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-default navbar-custom navbar-fixed-top">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header page-scroll">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="https://captainark.net/">Sysadmining. All day. Every day.</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/">Homepage</a></li>
<li><a href="/rss.xml">RSS</a></li>
<li><a href="/categories.html">Categories</a></li>
<li><a href="https://captainark.net/pages/about.html">About</a></li>
<li><a href="https://captainark.net/pages/resume.html">Resume</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container -->
</nav>
<!-- Page Header -->
<header class="intro-header" style="background-image: url('/bg.png')">
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-heading">
<h1>WebDAV with nginx</h1>
<span class="meta">Posted by
<a href="https://captainark.net/author/antoine-joubert.html">Antoine Joubert</a>
on Sat 26 March 2016
</span>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<!-- Post Content -->
<article>
<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>
</article>
<hr>
<div class="sharing">
</div>
<hr>
<div class="comments">
<h2>Comments !</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'captainark';
var disqus_identifier = 'webdav-with-nginx.html';
var disqus_url = 'https://captainark.net/webdav-with-nginx.html';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//captainark.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the comments.</noscript>
</div>
</div>
</div>
</div>
<hr>
<!-- Footer -->
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<ul class="list-inline text-center">
<li>
<a href="mailto:contact@captainark.net">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-envelope fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="https://twitter.com/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="https://github.com/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="http://www.last.fm/user/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-lastfm fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="https://steamcommunity.com/id/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-steam fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="http://www.twitch.tv/captainark">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-twitch fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">
Blog powered by <a href="http://getpelican.com">Pelican</a>,
which takes great advantage of <a href="http://python.org">Python</a>.
</p> </div>
</div>
</div>
</footer>
<!-- jQuery -->
<script src="https://captainark.net/theme/js/jquery.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="https://captainark.net/theme/js/bootstrap.min.js"></script>
<!-- Custom Theme JavaScript -->
<script src="https://captainark.net/theme/js/clean-blog.min.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-53658366-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<script type="text/javascript">
var disqus_shortname = 'captainark';
(function () {
var s = document.createElement('script'); s.async = true;
s.type = 'text/javascript';
s.src = '//' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
</body>
</html>