webdav with nginx #1
This commit is contained in:
parent
26f00c7265
commit
5ff622f450
358
content/webdav-nginx.md
Normal file
358
content/webdav-nginx.md
Normal 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 !
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
@ -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">
|
||||||
|
@ -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">
|
||||||
|
316
output/rss.xml
316
output/rss.xml
@ -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"><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>
|
<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"><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></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"><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>
|
<h2>The script</h2>
|
||||||
<p>For the script to work, you'll need to edit a few variable to match your configuration.</p>
|
<p>For the script to work, you'll need to edit a few variable to match your configuration.</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
550
output/webdav-with-nginx.html
Normal file
550
output/webdav-with-nginx.html
Normal 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">'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/'</span> > /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 '/ssl_/ s/^/#/' /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">'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'</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">&&</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 "";
|
||||||
|
|
||||||
|
return 444;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 default_server ssl http2;
|
||||||
|
listen [::]:443 default_server ipv6only=on ssl http2;
|
||||||
|
server_name "";
|
||||||
|
|
||||||
|
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">"Restricted access"</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"><</span><span class="n">YOUR</span> <span class="n">IP</span> <span class="n">HERE</span><span class="o">></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 "/run/nginx.pid"
|
||||||
|
start program = "/bin/systemctl start nginx"
|
||||||
|
stop program = "/bin/systemctl stop nginx"
|
||||||
|
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">"/usr/bin/letsencrypt"</span>
|
||||||
|
<span class="nv">CONFIG</span><span class="o">=</span><span class="s2">"/etc/letsencrypt/cli.ini"</span>
|
||||||
|
<span class="nv">MAILDEST</span><span class="o">=</span><span class="s2">"admin@example.com"</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">&&</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">"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."</span> <span class="p">|</span> mail -s <span class="s2">"Letsencrypt error on </span><span class="k">$(</span>hostname -f<span class="k">)</span><span class="s2">"</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 && 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 '/data webdav notanactualpassword' >> /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 "/root/bin/mount_davfs"
|
||||||
|
</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>
|
Loading…
Reference in New Issue
Block a user