Auto Rename Uploads with Timestamp
This page documents an automation pattern for Docusaurus sites: watch a static image folder and rename newly-uploaded files with a timestamp to prevent filename collisions.
- Watch a directory (example:
opt/docker-data/apps/docusaurus/site/static/img) withinotifywait. - On create/move events, rename files to
original_name-YYYYMMDDHHMM.ext(plus a numeric suffix on collisions). - Run it as a
systemd --userservice so it survives terminal sessions.
Renaming files is destructive for existing links. If you already referenced an image name in Markdown/MDX, renaming the file will break the link until you update the docs.
When this is useful
- You upload screenshots via SFTP or a file manager and want guaranteed unique names.
- You want a predictable naming scheme for later cleanup/search.
- You want to avoid manual "rename before upload" habits.
How it works
The workflow is:
The watcher should ignore:
- dotfiles (example:
.DS_Store) - partial uploads (example:
.part,.crdownload) - non-image extensions
Paths and unit names
Adjust these to your server layout:
- Watched directory:
/opt/docker-data/apps/docusaurus/site/static/img - Script location (example):
/home/rezriz/github/scripts/watch_rename_uploads.sh - Service name:
watch-rename-uploads.service - User unit path:
~/.config/systemd/user/watch-rename-uploads.service
Install dependencies
Install inotify-tools:
sudo apt update
sudo apt install -y inotify-tools
Watcher script
Keep the script in a stable location and make it executable.
Example watcher script
#!/usr/bin/env bash
set -euo pipefail
WATCH_DIR="/opt/docker-data/apps/docusaurus/site/static/img"
SETTLE_SECONDS="1"
# Only rename these extensions.
ALLOW_RE='\.(jpe?g|png|webp|gif|svg|avif)$'
inotifywait -m -e close_write -e moved_to --format '%w%f' "$WATCH_DIR" | while read -r path; do
name="$(basename "$path")"
# Ignore dotfiles and common temp extensions.
[[ "$name" == .* ]] && continue
[[ "$name" == *.tmp || "$name" == *.part || "$name" == *.crdownload ]] && continue
# Only rename allowed extensions.
[[ "$name" =~ $ALLOW_RE ]] || continue
sleep "$SETTLE_SECONDS"
base="${name%.*}"
ext="${name##*.}"
stamp="$(date +%Y%m%d%H%M)"
candidate="$WATCH_DIR/${base}-${stamp}.${ext}"
if [[ ! -e "$candidate" ]]; then
mv -n -- "$path" "$candidate"
continue
fi
for i in $(seq -w 1 99); do
candidate="$WATCH_DIR/${base}-${stamp}-${i}.${ext}"
if [[ ! -e "$candidate" ]]; then
mv -n -- "$path" "$candidate"
break
fi
done
done
systemd user service
Create a systemd --user unit that runs the script.
Example systemd user unit
[Unit]
Description=Watch Docusaurus static img folder and auto-rename uploads
After=default.target
[Service]
Type=simple
ExecStart=/home/rezriz/github/scripts/watch_rename_uploads.sh
Restart=always
RestartSec=2
[Install]
WantedBy=default.target
Enable and start it:
systemctl --user daemon-reload
systemctl --user enable --now watch-rename-uploads.service
Enable user lingering
If you want the service to run when you are logged out, enable lingering for the user:
sudo loginctl enable-linger rezriz
loginctl enable-linger allows the user's systemd --user instance to run without an active login session.
Use it only for accounts you trust and keep that account secured (SSH keys, strong password policy, MFA where possible).
Manage the service
Check status:
systemctl --user status watch-rename-uploads.service --no-pager --full
View logs:
journalctl --user -u watch-rename-uploads.service -f
Restart after changes:
systemctl --user restart watch-rename-uploads.service
Stop the service:
systemctl --user stop watch-rename-uploads.service
Troubleshooting
Nothing is being renamed
- Confirm the service is running.
- Confirm
WATCH_DIRmatches the real upload directory. - Run the script manually to see errors (permissions, missing
inotifywait).
Files rename before upload completes
Increase the settle delay (SETTLE_SECONDS) or adjust the inotifywait event list to fit your upload method.
You renamed a file that is already referenced
Search for the old filename in docs and update references, or rename the file back.