This guide covers deploying dsviewer as a persistent systemd service and exposing it publicly via a Cloudflare Tunnel with a custom domain.
Browser → https://directory-structure-viewer.vietml.com
↓
Cloudflare Tunnel (cloudflared)
↓
localhost:9876
↓
dsviewer (systemd service)
- dsviewer installed via
install.sh(see DEV_SETUP.md) sudoaccess on the server- A Cloudflare account with the
vietml.comdomain added
sudo nano /etc/systemd/system/dsviewer.servicePaste the following content — replace tqviet1978 with your actual username if different:
[Unit]
Description=Directory Structure Viewer
After=network.target
[Service]
Type=simple
User=tqviet1978
ExecStart=/home/tqviet1978/.dsviewer/bin/dsviewer --port 9876
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetSave and exit: Ctrl+O → Enter → Ctrl+X
# Reload systemd to pick up the new service file
sudo systemctl daemon-reload
# Enable the service to start automatically on boot
sudo systemctl enable dsviewer
# Start the service now
sudo systemctl start dsviewersudo systemctl status dsviewerExpected output:
● dsviewer.service - Directory Structure Viewer
Loaded: loaded (/etc/systemd/system/dsviewer.service; enabled)
Active: active (running) since ...
Main PID: 12345 (dsviewer)
Verify it is listening on the correct port:
ss -tlnp | grep 9876Expected output:
LISTEN 0 128 0.0.0.0:9876 0.0.0.0:* users:(("python",pid=12345,...))
Do a quick local test:
curl -s http://localhost:9876/ | head -5# View live logs
journalctl -u dsviewer -f
# View last 50 log lines
journalctl -u dsviewer -n 50
# Restart after config changes
sudo systemctl restart dsviewer
# Stop the service
sudo systemctl stop dsviewer
# Disable autostart on boot
sudo systemctl disable dsviewerCheck if it is already installed:
cloudflared --versionIf not installed, run the following for Debian 12:
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb \
-o cloudflared.deb
sudo dpkg -i cloudflared.deb
rm cloudflared.deb
# Confirm installation
cloudflared --versioncloudflared tunnel loginThis opens a browser window. Select the vietml.com domain to grant access. A credentials file will be saved to ~/.cloudflared/cert.pem.
cloudflared tunnel create dsviewerThe output will include a Tunnel ID — save it, you will need it in the next step:
Created tunnel dsviewer with id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
mkdir -p ~/.cloudflared
nano ~/.cloudflared/config.ymlPaste the following — replace <TUNNEL_ID> with the ID from the previous step:
tunnel: <TUNNEL_ID>
credentials-file: /home/tqviet1978/.cloudflared/<TUNNEL_ID>.json
ingress:
- hostname: directory-structure-viewer.vietml.com
service: http://localhost:9876
- service: http_status:404Save and exit: Ctrl+O → Enter → Ctrl+X
cloudflared tunnel route dns dsviewer directory-structure-viewer.vietml.comThis automatically creates a CNAME record in Cloudflare DNS pointing directory-structure-viewer.vietml.com to your tunnel.
Verify the record was created by logging into the Cloudflare dashboard → DNS → check for a CNAME entry for directory-structure-viewer.
# Install cloudflared as a system service
sudo cloudflared service install
# Enable autostart on boot
sudo systemctl enable cloudflared
# Start the service now
sudo systemctl start cloudflared
# Verify it is running
sudo systemctl status cloudflaredExpected output:
● cloudflared.service - cloudflared
Active: active (running) since ...
Run all checks in sequence:
# 1. Both services are running
sudo systemctl status dsviewer cloudflared
# 2. dsviewer is listening on port 9876
ss -tlnp | grep 9876
# 3. Local connectivity
curl -s http://localhost:9876/ | head -3
# 4. Public URL (allow up to 30s for DNS to propagate after first setup)
curl -s https://directory-structure-viewer.vietml.com/ | head -3Then open https://directory-structure-viewer.vietml.com in a browser — the login dialog should appear.
Log in with the default credentials:
Username: admin
Password: admin123
Since the app is publicly accessible, change the default password immediately:
~/.dsviewer/bin/dsviewer --change-passwordFollow the interactive prompts. Then restart the service to apply:
sudo systemctl restart dsviewerThe recommended way to update on a production server:
dsviewer --updateThe update script will:
- Stop the running
dsviewersystemd service automatically - Pull the latest application code from GitHub
- Replace files under
~/.dsviewer/(code only) - Restart the service automatically
Your data directory (~/.dsviewer/data/) and all credentials are preserved.
If the dsviewer command is not available in the current shell:
curl -fsSL https://raw.githubusercontent.com/cloudpad9/directory-structure-viewer-python/main/update.sh | bashCheck that the service restarted cleanly after the update:
# Confirm the new version
dsviewer --version
# Confirm the service is still running
sudo systemctl status dsviewer
# Check the logs for any startup errors
journalctl -u dsviewer -n 30Then do a quick end-to-end test:
curl -s http://localhost:9876/ | head -3The update script does not keep a backup. If the new version has an issue, roll back by reinstalling from a specific commit:
# Stop the service
sudo systemctl stop dsviewer
# Re-run the installer — it will overwrite the current installation
curl -fsSL https://raw.githubusercontent.com/cloudpad9/directory-structure-viewer-python/main/install.sh | bash
# Restart the service
sudo systemctl start dsviewer| Symptom | Likely cause | Fix |
|---|---|---|
systemctl status dsviewer shows failed |
Wrong ExecStart path or permission issue |
Check path with which dsviewer or ls ~/.dsviewer/bin/; verify User= is correct |
Port 9876 not in ss -tlnp output |
Service not started or crashed | Run journalctl -u dsviewer -n 50 to see the error |
curl localhost:9876 works but public URL returns 502 |
cloudflared not running or wrong port in config | Check sudo systemctl status cloudflared and verify port in ~/.cloudflared/config.yml |
| Public URL returns a Cloudflare 1033 error | Tunnel is down | Run sudo systemctl restart cloudflared |
| DNS not resolving yet | DNS propagation delay | Wait 1–2 minutes after first setup; check with dig directory-structure-viewer.vietml.com |
| Login works locally but session expires instantly on public URL | Clock skew between server and Cloudflare | Sync server time with sudo timedatectl set-ntp true |
cloudflared service install fails |
Missing sudo or credentials not found |
Ensure you ran cloudflared tunnel login first and ~/.cloudflared/cert.pem exists |