Init Script Setup
Automated initialization scripts for FileBrowser using the API. Works across Docker, Docker Compose, Kubernetes, and bare metal deployments.
Overview
FileBrowser creates a default admin user on first startup using credentials from your configuration. Init scripts use this account to:
- Wait for FileBrowser to be ready (health check)
- Authenticate using admin credentials
- Receive a JWT token
- Perform setup tasks (create users, configure settings, etc.)
Quick Start
Basic Init Script
Create init-filebrowser.sh
:
#!/bin/bash
set -e
FILEBROWSER_URL="${FILEBROWSER_URL:-http://localhost:8080}"
ADMIN_USERNAME="${FILEBROWSER_ADMIN_USERNAME:-admin}"
ADMIN_PASSWORD="${FILEBROWSER_ADMIN_PASSWORD:-admin}"
# Wait for FileBrowser
until curl -f -s "${FILEBROWSER_URL}/health" > /dev/null 2>&1; do
echo "Waiting for FileBrowser..."
sleep 2
done
# Get auth token
TOKEN=$(curl -s -H "X-Password: ${ADMIN_PASSWORD}" \
"${FILEBROWSER_URL}/api/auth/login?username=${ADMIN_USERNAME}")
# Create a user
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"which": [],
"data": {
"username": "demo",
"password": "demo123",
"loginMethod": "password",
"permissions": {
"admin": false,
"modify": true,
"share": true
}
}
}' \
"${FILEBROWSER_URL}/api/users"
echo "Initialization complete!"
Make it executable:
chmod +x init-filebrowser.sh
Docker Compose Setup
docker-compose.yml
:
services:
filebrowser:
image: your-filebrowser:latest
ports:
- "8080:8080"
environment:
- FILEBROWSER_ADMIN_USERNAME=admin
- FILEBROWSER_ADMIN_PASSWORD=${ADMIN_PASSWORD}
volumes:
- ./config.yaml:/config.yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 5s
timeout: 3s
retries: 10
filebrowser-init:
image: curlimages/curl:latest
depends_on:
filebrowser:
condition: service_healthy
environment:
- FILEBROWSER_URL=http://filebrowser:8080
- FILEBROWSER_ADMIN_USERNAME=admin
- FILEBROWSER_ADMIN_PASSWORD=${ADMIN_PASSWORD}
volumes:
- ./init-filebrowser.sh:/scripts/init-filebrowser.sh:ro
command: sh /scripts/init-filebrowser.sh
restart: "no"
Start services:
export ADMIN_PASSWORD="your-secure-password"
docker-compose up -d
docker-compose logs filebrowser-init
Kubernetes Setup
Create filebrowser-init-job.yaml
:
apiVersion: v1
kind: Secret
metadata:
name: filebrowser-secrets
type: Opaque
stringData:
admin-username: admin
admin-password: changeme-in-production
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebrowser-init-script
data:
init.sh: |
#!/bin/sh
set -e
until curl -f -s "${FILEBROWSER_URL}/health" > /dev/null 2>&1; do
echo "Waiting for FileBrowser..."
sleep 2
done
TOKEN=$(curl -s -H "X-Password: ${ADMIN_PASSWORD}" \
"${FILEBROWSER_URL}/api/auth/login?username=${ADMIN_USERNAME}")
echo "Initialization complete!"
---
apiVersion: batch/v1
kind: Job
metadata:
name: filebrowser-init
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: init
image: curlimages/curl:latest
command: ["/bin/sh", "/scripts/init.sh"]
env:
- name: FILEBROWSER_URL
value: "http://filebrowser.default.svc.cluster.local"
- name: ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: filebrowser-secrets
key: admin-username
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: filebrowser-secrets
key: admin-password
volumeMounts:
- name: init-script
mountPath: /scripts
volumes:
- name: init-script
configMap:
name: filebrowser-init-script
defaultMode: 0755
Deploy:
kubectl apply -f filebrowser-init-job.yaml
kubectl logs job/filebrowser-init
Common API Operations
Create User
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"which": [],
"data": {
"username": "newuser",
"password": "password123",
"loginMethod": "password",
"permissions": {
"admin": false,
"modify": true,
"share": true
}
}
}' \
http://localhost:8080/api/users
Create Share
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"path": "/shared-folder",
"source": "files",
"expire": "2025-12-31T23:59:59Z",
"password": "sharepass123"
}' \
http://localhost:8080/api/share
List Users
curl -H "Authorization: Bearer ${TOKEN}" \
http://localhost:8080/api/users
Best Practices
Security
- Never hardcode credentials - use environment variables or secrets
- Rotate admin password after first login
- Use HTTPS in production
- Limit network exposure
Reliability
- Wait for health checks before init
- Make scripts idempotent (handle “already exists” errors)
- Set timeouts and retries
- Log all actions
Maintainability
- Version control init scripts
- Document custom operations
- Use functions for modularity
- Test in staging first
Troubleshooting
For common issues and solutions, see the Troubleshooting guide.
Complete Examples
Full Production Script
Create init-filebrowser.sh
with comprehensive error handling:
#!/bin/bash
set -e
# Configuration from environment
FILEBROWSER_URL="${FILEBROWSER_URL:-http://localhost:8080}"
ADMIN_USERNAME="${FILEBROWSER_ADMIN_USERNAME:-admin}"
ADMIN_PASSWORD="${FILEBROWSER_ADMIN_PASSWORD:-admin}"
MAX_RETRIES="${MAX_RETRIES:-30}"
RETRY_DELAY="${RETRY_DELAY:-2}"
echo "FileBrowser initialization script started"
echo "Target URL: ${FILEBROWSER_URL}"
# Function to wait for FileBrowser to be ready
wait_for_filebrowser() {
local retries=0
echo "Waiting for FileBrowser to be ready..."
while [ $retries -lt $MAX_RETRIES ]; do
if curl -f -s "${FILEBROWSER_URL}/health" > /dev/null 2>&1; then
echo "FileBrowser is ready!"
return 0
fi
retries=$((retries + 1))
echo "Attempt ${retries}/${MAX_RETRIES} - waiting ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
done
echo "ERROR: FileBrowser failed to start after ${MAX_RETRIES} attempts"
return 1
}
# Function to get auth token
get_auth_token() {
local username=$1
local password=$2
echo "Logging in as ${username}..."
local response
response=$(curl -s -w "\n%{http_code}" \
-H "X-Password: ${password}" \
"${FILEBROWSER_URL}/api/auth/login?username=${username}")
local http_code=$(echo "$response" | tail -n1)
local token=$(echo "$response" | head -n-1)
if [ "$http_code" -eq 200 ] && [ -n "$token" ]; then
echo "Successfully authenticated!"
echo "$token"
return 0
else
echo "ERROR: Authentication failed (HTTP ${http_code})"
return 1
fi
}
# Function to create user
create_user() {
local token=$1
local username=$2
local password=$3
local is_admin=${4:-false}
echo "Creating user: ${username}..."
local response
response=$(curl -s -w "\n%{http_code}" \
-X POST \
-H "Authorization: Bearer ${token}" \
-H "Content-Type: application/json" \
-d "{
\"which\": [],
\"data\": {
\"username\": \"${username}\",
\"password\": \"${password}\",
\"loginMethod\": \"password\",
\"permissions\": {
\"admin\": ${is_admin},
\"modify\": true,
\"share\": true,
\"create\": true,
\"rename\": true,
\"delete\": true,
\"download\": true
},
\"scopes\": []
}
}" \
"${FILEBROWSER_URL}/api/users")
local http_code=$(echo "$response" | tail -n1)
if [ "$http_code" -eq 201 ]; then
echo "User ${username} created successfully"
return 0
elif [ "$http_code" -eq 409 ] || [ "$http_code" -eq 500 ]; then
echo "User ${username} already exists or conflicts"
return 0
else
echo "WARNING: Failed to create user ${username} (HTTP ${http_code})"
echo "$response" | head -n-1
return 1
fi
}
# Main execution
main() {
# Wait for FileBrowser to be ready
if ! wait_for_filebrowser; then
exit 1
fi
# Get authentication token
TOKEN=$(get_auth_token "$ADMIN_USERNAME" "$ADMIN_PASSWORD")
if [ -z "$TOKEN" ]; then
echo "ERROR: Failed to get authentication token"
exit 1
fi
echo ""
echo "Running initialization tasks..."
echo "Token: ${TOKEN:0:20}..."
echo ""
# Example: Create additional users
create_user "$TOKEN" "demo" "demo123" false
create_user "$TOKEN" "viewer" "viewer123" false
# Note: Settings cannot be updated via API - they must be configured
# through the config.yaml file or environment variables before startup
echo ""
echo "Initialization complete!"
}
# Run main function
main "$@"
Make the script executable:
chmod +x init-filebrowser.sh
Production Docker Compose Setup
docker-compose.yml
:
version: '3.8'
services:
filebrowser:
image: your-filebrowser:latest
ports:
- "8080:8080"
environment:
- FILEBROWSER_ADMIN_USERNAME=admin
- FILEBROWSER_ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme}
volumes:
- ./data:/data
- ./database:/database
- ./config.yaml:/config.yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
filebrowser-init:
image: curlimages/curl:latest
depends_on:
filebrowser:
condition: service_healthy
environment:
- FILEBROWSER_URL=http://filebrowser:8080
- FILEBROWSER_ADMIN_USERNAME=admin
- FILEBROWSER_ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme}
volumes:
- ./init-filebrowser.sh:/scripts/init-filebrowser.sh:ro
command: sh /scripts/init-filebrowser.sh
restart: "no"
volumes:
data:
database:
Production Setup with Secrets
Create .env
file (DO NOT commit to git):
ADMIN_PASSWORD=your-secure-password-here
Update docker-compose.yml
:
version: '3.8'
services:
filebrowser:
image: your-filebrowser:latest
ports:
- "8080:8080"
env_file:
- .env
environment:
- FILEBROWSER_ADMIN_USERNAME=admin
- FILEBROWSER_ADMIN_PASSWORD=${ADMIN_PASSWORD}
volumes:
- data:/data
- database:/database
- ./config.yaml:/config.yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
restart: unless-stopped
filebrowser-init:
image: curlimages/curl:latest
depends_on:
filebrowser:
condition: service_healthy
env_file:
- .env
environment:
- FILEBROWSER_URL=http://filebrowser:8080
- FILEBROWSER_ADMIN_USERNAME=admin
- FILEBROWSER_ADMIN_PASSWORD=${ADMIN_PASSWORD}
volumes:
- ./init-filebrowser.sh:/scripts/init-filebrowser.sh:ro
command: sh /scripts/init-filebrowser.sh
restart: "no"
volumes:
data:
driver: local
database:
driver: local
Advanced Kubernetes Setup
Create filebrowser-init-job.yaml
:
apiVersion: v1
kind: Secret
metadata:
name: filebrowser-secrets
namespace: default
type: Opaque
stringData:
admin-username: admin
admin-password: changeme-in-production
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebrowser-init-script
namespace: default
data:
init.sh: |
#!/bin/sh
set -e
echo "Waiting for FileBrowser to be ready..."
RETRIES=0
MAX_RETRIES=30
until curl -f -s "${FILEBROWSER_URL}/health" > /dev/null 2>&1; do
RETRIES=$((RETRIES + 1))
if [ $RETRIES -ge $MAX_RETRIES ]; then
echo "ERROR: FileBrowser not ready after ${MAX_RETRIES} attempts"
exit 1
fi
echo "Waiting... (${RETRIES}/${MAX_RETRIES})"
sleep 2
done
echo "FileBrowser is ready!"
echo "Getting auth token..."
TOKEN=$(curl -s -H "X-Password: ${ADMIN_PASSWORD}" \
"${FILEBROWSER_URL}/api/auth/login?username=${ADMIN_USERNAME}")
if [ -z "$TOKEN" ]; then
echo "ERROR: Failed to authenticate"
exit 1
fi
echo "Authenticated successfully!"
echo "Token: ${TOKEN:0:20}..."
# Create demo user
echo "Creating demo user..."
HTTP_CODE=$(curl -s -w "%{http_code}" -o /dev/null \
-X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"which":[],"data":{"username":"demo","password":"demo123","loginMethod":"password","permissions":{"admin":false,"modify":true,"share":true,"create":true,"rename":true,"delete":true,"download":true},"scopes":[]}}' \
"${FILEBROWSER_URL}/api/users")
if [ "$HTTP_CODE" = "201" ]; then
echo "Demo user created successfully"
elif [ "$HTTP_CODE" = "409" ] || [ "$HTTP_CODE" = "500" ]; then
echo "Demo user already exists"
else
echo "WARNING: Failed to create demo user (HTTP ${HTTP_CODE})"
fi
echo "Initialization complete!"
---
apiVersion: batch/v1
kind: Job
metadata:
name: filebrowser-init
namespace: default
spec:
ttlSecondsAfterFinished: 300
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
containers:
- name: init
image: curlimages/curl:latest
command: ["/bin/sh", "/scripts/init.sh"]
env:
- name: FILEBROWSER_URL
value: "http://filebrowser.default.svc.cluster.local"
- name: ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: filebrowser-secrets
key: admin-username
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: filebrowser-secrets
key: admin-password
volumeMounts:
- name: init-script
mountPath: /scripts
volumes:
- name: init-script
configMap:
name: filebrowser-init-script
defaultMode: 0755
SystemD Integration
Create /etc/systemd/system/filebrowser.service
:
[Unit]
Description=FileBrowser Service
After=network.target
[Service]
Type=simple
User=filebrowser
Group=filebrowser
Environment="FILEBROWSER_ADMIN_USERNAME=admin"
Environment="FILEBROWSER_ADMIN_PASSWORD=changeme"
EnvironmentFile=-/etc/filebrowser/env
WorkingDirectory=/opt/filebrowser
ExecStart=/opt/filebrowser/filebrowser
ExecStartPost=/bin/sleep 5
ExecStartPost=/opt/filebrowser/init-filebrowser.sh
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Create /etc/filebrowser/env
:
FILEBROWSER_ADMIN_USERNAME=admin
FILEBROWSER_ADMIN_PASSWORD=your-secure-password
FILEBROWSER_URL=http://localhost:8080
Setup Commands
# Create user
sudo useradd -r -s /bin/false filebrowser
# Create directories
sudo mkdir -p /opt/filebrowser
sudo mkdir -p /etc/filebrowser
sudo mkdir -p /var/lib/filebrowser
# Copy files
sudo cp filebrowser /opt/filebrowser/
sudo cp init-filebrowser.sh /opt/filebrowser/
sudo cp config.yaml /opt/filebrowser/
sudo chmod +x /opt/filebrowser/filebrowser
sudo chmod +x /opt/filebrowser/init-filebrowser.sh
# Set permissions
sudo chown -R filebrowser:filebrowser /opt/filebrowser
sudo chown -R filebrowser:filebrowser /var/lib/filebrowser
sudo chmod 600 /etc/filebrowser/env
# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable filebrowser
sudo systemctl start filebrowser
# Check status
sudo systemctl status filebrowser
sudo journalctl -u filebrowser -f
Advanced API Operations
Create User with Full Permissions
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"which": [],
"data": {
"username": "newuser",
"password": "password123",
"loginMethod": "password",
"permissions": {
"admin": false,
"modify": true,
"share": true,
"create": true,
"rename": true,
"delete": true,
"download": true
},
"scopes": []
}
}' \
http://localhost:8080/api/users
Create Share
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"path": "/shared-folder",
"source": "files",
"expire": "2025-12-31T23:59:59Z",
"password": "sharepass123",
"downloadsLimit": 10,
"allowUpload": false,
"disableFileViewer": false,
"disableAnonymous": false,
"maxBandwidth": 0,
"title": "My Share",
"description": "Shared files"
}' \
http://localhost:8080/api/share
Get Settings (Read-Only)
Settings cannot be updated via API. They must be configured in config.yaml
before starting FileBrowser.
# Get all settings
curl -H "Authorization: Bearer ${TOKEN}" \
http://localhost:8080/api/settings
# Get specific property
curl -H "Authorization: Bearer ${TOKEN}" \
"http://localhost:8080/api/settings?property=userDefaults"
# Available properties: userDefaults, frontend, auth, server, sources
Get Settings as YAML
# Get full configuration with comments
curl -H "Authorization: Bearer ${TOKEN}" \
"http://localhost:8080/api/settings/config?full=true&comments=true"
# Get only non-default values
curl -H "Authorization: Bearer ${TOKEN}" \
"http://localhost:8080/api/settings/config?full=false&comments=false"
Troubleshooting
Init Script Fails to Connect
Problem: Script cannot reach FileBrowser service
Solutions:
# Check service is running
docker-compose ps
kubectl get pods
# Check health endpoint
curl http://localhost:8080/health
# Verify network connectivity
ping filebrowser
nslookup filebrowser.default.svc.cluster.local
# Check firewall rules
iptables -L
kubectl get networkpolicies
Authentication Fails
Problem: Cannot get token from login API
Solutions:
# Verify credentials are correct
echo "Username: ${FILEBROWSER_ADMIN_USERNAME}"
echo "Password: ${FILEBROWSER_ADMIN_PASSWORD}"
# Test login manually
curl -v -H "X-Password: admin" \
"http://localhost:8080/api/auth/login?username=admin"
# Check logs for authentication errors
docker-compose logs filebrowser
kubectl logs deployment/filebrowser
Init Job Runs Multiple Times
Problem: Kubernetes Job retries unnecessarily
Solutions:
- Ensure script exits with code 0 on success
- Set
backoffLimit
in Job spec - Make script idempotent (handle existing resources)
- Add
ttlSecondsAfterFinished
to clean up completed jobs
Permission Denied Errors
Problem: Script cannot execute or access files
Solutions:
# Make script executable
chmod +x init-filebrowser.sh
# Check file ownership
ls -la init-filebrowser.sh
# Verify volume mounts in Docker
docker-compose exec filebrowser-init ls -la /scripts
# Check SecurityContext in Kubernetes
kubectl describe pod <pod-name>
Cannot Update Settings
Problem: Trying to update settings via API
Solution:
Settings are read-only via the API. You must update the config.yaml
file and restart FileBrowser for changes to take effect. This is by design to ensure configuration consistency.
Configuration via config.yaml
Since settings cannot be updated via the API, you must configure FileBrowser through the config.yaml
file. Here’s an example:
server:
port: 8080
baseURL: /
database: /database/database.db
log: stdout
sources:
- name: files
path: /data
auth:
adminUsername: admin
adminPassword: changeme
key: random-secret-key
tokenExpirationHours: 168
methods:
passwordAuth:
enabled: true
signup: false
enforcedOtp: false
userDefaults:
permissions:
admin: false
modify: true
share: true
create: true
rename: true
delete: true
download: true
scopes: []
frontend:
name: "FileBrowser"
disableExternal: false
files: []
Advantages of This Approach
No Code Changes Required
- Uses existing authentication API
- No special init mode needed
- Works with current codebase as-is
Security
- Credentials passed via environment variables
- No secrets in process list or command history
- Compatible with secrets management systems
Cloud-Native
- Works with Kubernetes Secrets
- Supports Docker Compose secrets
- Compatible with HashiCorp Vault, AWS Secrets Manager, etc.
Flexibility
- Works across all deployment types
- Easy to extend with additional setup tasks
- Scripts can be customized per environment
Familiar Patterns
- Similar to database migration scripts
- Standard init container pattern
- DevOps teams will recognize the approach