2016-03-26 15:36:09 +01:00
<!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" >
< 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]-->
2016-03-26 15:40:16 +01:00
< 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 years ..." >
2016-03-26 15:36:09 +01:00
< 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" >
2016-05-22 15:22:00 +02:00
< meta property = "article:author" content = "https://captainark.net/author/antoine-joubert.html" >
2016-03-26 15:36:09 +01:00
< 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" >
2016-03-26 15:40:16 +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 years ..." >
2016-03-26 15:36:09 +01:00
< meta property = "og:image" content = "https://captainark.net//bg.png" >
2016-05-22 15:22:00 +02:00
< meta name = "twitter:card" content = "summary_large_image" >
< meta name = "twitter:site" content = "@captainark" >
< meta name = "twitter:title" content = "WebDAV with nginx" >
< meta name = "twitter:image" content = "https://captainark.net//bg.png" >
< meta name = "twitter: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 years ..." >
2016-03-26 15:36:09 +01:00
< / 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 >
2016-03-26 15:40:16 +01:00
< 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 years now, and I still don't have anything bad to say about them.< / p >
2016-03-26 15:36:09 +01:00
< 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 >