Created
April 14, 2025 15:16
-
-
Save bogdanscarwash/bfa7eea483aab7451d545be91346e16c to your computer and use it in GitHub Desktop.
Universal WebDAV Server Setup Script for Debian 12. Works on both standard Debian 12 and WSL environments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Universal WebDAV Server Setup Script for Debian 12 | |
# Works on both standard Debian 12 and WSL environments | |
# Exit on any error | |
set -e | |
# Configuration variables | |
WEBDAV_DIR="/var/www/webdav" | |
WEBDAV_CONF="/etc/apache2/sites-available/webdav.conf" | |
WEBDAV_USER="webdav_user" | |
LOCK_DB="/var/lock/apache2/DAVLock" | |
HTML_INTERFACE=true | |
# Function to check if running as root | |
check_root() { | |
if [ "$(id -u)" -ne 0 ]; then | |
echo "This script must be run as root. Please use sudo." | |
exit 1 | |
fi | |
} | |
# Function to detect environment (WSL vs standard Debian) | |
detect_environment() { | |
if grep -q Microsoft /proc/version || grep -q microsoft /proc/version; then | |
echo "WSL environment detected. Using service commands." | |
ENVIRONMENT="wsl" | |
else | |
echo "Standard Debian environment detected. Using systemctl." | |
ENVIRONMENT="standard" | |
fi | |
} | |
# Function to update system | |
update_system() { | |
echo "Updating system packages..." | |
apt update | |
apt upgrade -y | |
} | |
# Function to install Apache2 | |
install_apache() { | |
echo "Installing Apache2..." | |
apt install -y apache2 | |
echo "Installing apache2-utils for htpasswd utility..." | |
apt install -y apache2-utils | |
echo "Starting Apache2 service..." | |
if [ "$ENVIRONMENT" = "wsl" ]; then | |
service apache2 start || true | |
else | |
systemctl enable apache2 | |
systemctl start apache2 | |
fi | |
} | |
# Function to enable WebDAV modules | |
enable_webdav_modules() { | |
echo "Enabling WebDAV modules..." | |
a2enmod dav | |
a2enmod dav_fs | |
a2enmod alias | |
echo "Restarting Apache2..." | |
if [ "$ENVIRONMENT" = "wsl" ]; then | |
service apache2 restart | |
else | |
systemctl restart apache2 | |
fi | |
} | |
# Function to create and configure WebDAV directory | |
configure_webdav_directory() { | |
echo "Creating WebDAV directory at $WEBDAV_DIR..." | |
mkdir -p $WEBDAV_DIR | |
echo "Setting ownership to www-data..." | |
chown -R www-data:www-data $WEBDAV_DIR | |
echo "Creating lock directory..." | |
mkdir -p $(dirname $LOCK_DB) | |
chown -R www-data:www-data $(dirname $LOCK_DB) | |
# Simple configuration directly in default site | |
echo "Creating WebDAV configuration in default site..." | |
cat > /etc/apache2/sites-available/000-default.conf << EOF | |
<VirtualHost *:80> | |
ServerAdmin webmaster@localhost | |
DocumentRoot /var/www/html | |
# WebDAV configuration | |
Alias /webdav $WEBDAV_DIR | |
<Directory $WEBDAV_DIR> | |
Options Indexes FollowSymLinks | |
AllowOverride None | |
Require all granted | |
DAV On | |
AuthType Basic | |
AuthName "WebDAV Server" | |
AuthUserFile /etc/apache2/.htpasswd | |
Require valid-user | |
</Directory> | |
DavLockDB $LOCK_DB | |
ErrorLog \${APACHE_LOG_DIR}/error.log | |
CustomLog \${APACHE_LOG_DIR}/access.log combined | |
</VirtualHost> | |
EOF | |
} | |
# Function to create user authentication | |
setup_authentication() { | |
echo "Creating authentication file with user $WEBDAV_USER..." | |
htpasswd -c /etc/apache2/.htpasswd $WEBDAV_USER | |
echo "Reloading Apache2 configuration..." | |
if [ "$ENVIRONMENT" = "wsl" ]; then | |
service apache2 reload | |
else | |
systemctl reload apache2 | |
fi | |
} | |
# Function to create web interface | |
create_web_interface() { | |
if [ "$HTML_INTERFACE" = true ]; then | |
echo "Creating web interface..." | |
cat > $WEBDAV_DIR/index.html << 'EOF' | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>WebDAV Browser</title> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
margin: 0; | |
padding: 20px; | |
background: #f5f5f5; | |
} | |
.container { | |
max-width: 900px; | |
margin: 0 auto; | |
background: white; | |
padding: 20px; | |
border-radius: 5px; | |
box-shadow: 0 2px 10px rgba(0,0,0,0.1); | |
} | |
h1 { | |
color: #333; | |
border-bottom: 1px solid #eee; | |
padding-bottom: 10px; | |
} | |
#file-list { | |
margin-top: 20px; | |
} | |
.file-item { | |
padding: 10px; | |
border-bottom: 1px solid #eee; | |
display: flex; | |
align-items: center; | |
} | |
.file-item:hover { | |
background: #f9f9f9; | |
} | |
.file-icon { | |
margin-right: 10px; | |
color: #555; | |
} | |
.file-name { | |
flex-grow: 1; | |
} | |
.file-actions { | |
display: flex; | |
gap: 10px; | |
} | |
.btn { | |
padding: 6px 12px; | |
border: none; | |
border-radius: 4px; | |
cursor: pointer; | |
font-size: 14px; | |
} | |
.btn-primary { | |
background: #4285f4; | |
color: white; | |
} | |
.btn-danger { | |
background: #ea4335; | |
color: white; | |
} | |
.dropzone { | |
border: 2px dashed #ccc; | |
border-radius: 5px; | |
padding: 25px; | |
text-align: center; | |
margin: 20px 0; | |
background: #f9f9f9; | |
} | |
.dropzone.highlight { | |
border-color: #4285f4; | |
background: #e8f0fe; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>WebDAV File Browser</h1> | |
<div class="dropzone" id="drop-area"> | |
<p>Drag & drop files here or</p> | |
<input type="file" id="file-input" multiple style="display: none;"> | |
<button class="btn btn-primary" onclick="document.getElementById('file-input').click()">Select Files</button> | |
</div> | |
<div id="file-list"> | |
<!-- Files will be listed here --> | |
<p>Loading files...</p> | |
</div> | |
</div> | |
<script> | |
// Simple WebDAV client using browser's built-in fetch API | |
const webdavClient = { | |
baseUrl: window.location.href, | |
// List files in the current directory | |
async listFiles() { | |
try { | |
const response = await fetch(this.baseUrl, { | |
method: 'PROPFIND', | |
headers: { | |
'Depth': '1', | |
'Content-Type': 'application/xml' | |
}, | |
credentials: 'include' | |
}); | |
if (response.ok) { | |
const text = await response.text(); | |
const parser = new DOMParser(); | |
const xmlDoc = parser.parseFromString(text, "text/xml"); | |
const responses = xmlDoc.getElementsByTagNameNS("DAV:", "response"); | |
const files = []; | |
for (let i = 1; i < responses.length; i++) { // Skip first (current directory) | |
const href = responses[i].getElementsByTagNameNS("DAV:", "href")[0].textContent; | |
const prop = responses[i].getElementsByTagNameNS("DAV:", "propstat")[0] | |
.getElementsByTagNameNS("DAV:", "prop")[0]; | |
const isCollection = prop.getElementsByTagNameNS("DAV:", "resourcetype")[0] | |
.getElementsByTagNameNS("DAV:", "collection").length > 0; | |
files.push({ | |
href: href, | |
name: decodeURIComponent(href.split('/').filter(Boolean).pop()), | |
isDirectory: isCollection | |
}); | |
} | |
return files; | |
} else { | |
throw new Error(`Failed to list files: ${response.status}`); | |
} | |
} catch (error) { | |
console.error("Error listing files:", error); | |
return []; | |
} | |
}, | |
// Download a file | |
downloadFile(href) { | |
window.location.href = href; | |
}, | |
// Delete a file | |
async deleteFile(href) { | |
try { | |
const response = await fetch(href, { | |
method: 'DELETE', | |
credentials: 'include' | |
}); | |
if (response.ok) { | |
return true; | |
} else { | |
throw new Error(`Failed to delete file: ${response.status}`); | |
} | |
} catch (error) { | |
console.error("Error deleting file:", error); | |
return false; | |
} | |
}, | |
// Upload a file | |
async uploadFile(file, progressCallback) { | |
try { | |
const url = this.baseUrl + encodeURIComponent(file.name); | |
const response = await fetch(url, { | |
method: 'PUT', | |
body: file, | |
credentials: 'include' | |
}); | |
if (response.ok) { | |
return true; | |
} else { | |
throw new Error(`Failed to upload file: ${response.status}`); | |
} | |
} catch (error) { | |
console.error("Error uploading file:", error); | |
return false; | |
} | |
}, | |
// Create a directory | |
async createDirectory(name) { | |
try { | |
const url = this.baseUrl + encodeURIComponent(name); | |
const response = await fetch(url, { | |
method: 'MKCOL', | |
credentials: 'include' | |
}); | |
if (response.ok) { | |
return true; | |
} else { | |
throw new Error(`Failed to create directory: ${response.status}`); | |
} | |
} catch (error) { | |
console.error("Error creating directory:", error); | |
return false; | |
} | |
} | |
}; | |
// Render file list | |
async function renderFileList() { | |
const fileListEl = document.getElementById('file-list'); | |
fileListEl.innerHTML = '<p>Loading files...</p>'; | |
const files = await webdavClient.listFiles(); | |
if (files.length === 0) { | |
fileListEl.innerHTML = '<p>No files found.</p>'; | |
return; | |
} | |
let html = ''; | |
files.forEach(file => { | |
html += ` | |
<div class="file-item"> | |
<div class="file-icon">${file.isDirectory ? '๐' : '๐'}</div> | |
<div class="file-name">${file.name}</div> | |
<div class="file-actions"> | |
<button class="btn btn-primary" onclick="downloadFile('${file.href}')">Download</button> | |
<button class="btn btn-danger" onclick="deleteFile('${file.href}', '${file.name}')">Delete</button> | |
</div> | |
</div> | |
`; | |
}); | |
html += ` | |
<div class="file-item"> | |
<button class="btn btn-primary" onclick="promptCreateDirectory()">Create Folder</button> | |
</div> | |
`; | |
fileListEl.innerHTML = html; | |
} | |
// Download file | |
function downloadFile(href) { | |
webdavClient.downloadFile(href); | |
} | |
// Delete file | |
async function deleteFile(href, name) { | |
if (confirm(`Are you sure you want to delete "${name}"?`)) { | |
const success = await webdavClient.deleteFile(href); | |
if (success) { | |
renderFileList(); | |
} else { | |
alert('Failed to delete file'); | |
} | |
} | |
} | |
// Create directory | |
function promptCreateDirectory() { | |
const name = prompt('Enter folder name:'); | |
if (name) { | |
webdavClient.createDirectory(name).then(success => { | |
if (success) { | |
renderFileList(); | |
} else { | |
alert('Failed to create folder'); | |
} | |
}); | |
} | |
} | |
// File upload handling | |
const dropArea = document.getElementById('drop-area'); | |
const fileInput = document.getElementById('file-input'); | |
dropArea.addEventListener('dragover', (e) => { | |
e.preventDefault(); | |
dropArea.classList.add('highlight'); | |
}); | |
dropArea.addEventListener('dragleave', () => { | |
dropArea.classList.remove('highlight'); | |
}); | |
dropArea.addEventListener('drop', (e) => { | |
e.preventDefault(); | |
dropArea.classList.remove('highlight'); | |
const files = e.dataTransfer.files; | |
handleFiles(files); | |
}); | |
fileInput.addEventListener('change', () => { | |
const files = fileInput.files; | |
handleFiles(files); | |
}); | |
async function handleFiles(files) { | |
for (const file of files) { | |
const success = await webdavClient.uploadFile(file); | |
if (success) { | |
console.log(`Uploaded: ${file.name}`); | |
} else { | |
console.error(`Failed to upload: ${file.name}`); | |
} | |
} | |
renderFileList(); | |
} | |
// Initialize | |
document.addEventListener('DOMContentLoaded', () => { | |
renderFileList(); | |
}); | |
</script> | |
</body> | |
</html> | |
EOF | |
chown www-data:www-data $WEBDAV_DIR/index.html | |
echo "Web interface created successfully." | |
fi | |
} | |
# Function to check and display server status | |
check_server() { | |
echo "Checking Apache2 status..." | |
if [ "$ENVIRONMENT" = "wsl" ]; then | |
service apache2 status || true | |
else | |
systemctl status apache2 --no-pager | |
fi | |
echo -e "\nWebDAV server setup complete!" | |
echo "You can access your WebDAV server at: http://localhost/webdav" | |
echo "Use the username $WEBDAV_USER and the password you provided" | |
if [ "$ENVIRONMENT" = "wsl" ]; then | |
echo -e "\nNOTE: Since you're using WSL, you'll need to start Apache manually after system restarts with:" | |
echo "sudo service apache2 start" | |
fi | |
if [ "$HTML_INTERFACE" = true ]; then | |
echo -e "\nA web-based file browser interface has been installed." | |
echo "Access it at http://localhost/webdav/" | |
fi | |
} | |
# Main execution | |
main() { | |
check_root | |
detect_environment | |
update_system | |
install_apache | |
enable_webdav_modules | |
configure_webdav_directory | |
setup_authentication | |
create_web_interface | |
check_server | |
} | |
# Run the script | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment