mirror of
https://github.com/ChrispyBacon-dev/DockFlare.git
synced 2026-04-26 10:50:43 +00:00
non-root enviroment and smaller bugfixes
This commit is contained in:
parent
1822b74a52
commit
d2a0101aff
10 changed files with 222 additions and 69 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -54,6 +54,7 @@ npm-debug.log*
|
|||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
AGENTS.md
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
|
|
|
|||
46
README.MD
46
README.MD
|
|
@ -83,6 +83,34 @@ Before you begin, ensure you have the following:
|
|||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
docker-socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:v0.4.1
|
||||
container_name: docker-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- CONTAINERS=1
|
||||
- EVENTS=1
|
||||
- NETWORKS=1
|
||||
- IMAGES=1
|
||||
- POST=1
|
||||
- PING=1
|
||||
- INFO=1
|
||||
- EXEC=1
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
dockflare-init:
|
||||
image: alpine:3.20
|
||||
command: ["sh", "-c", "chown -R 65532:65532 /app/data"]
|
||||
volumes:
|
||||
- dockflare_data:/app/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
restart: "no"
|
||||
|
||||
dockflare:
|
||||
image: alplat/dockflare:stable
|
||||
container_name: dockflare
|
||||
|
|
@ -90,13 +118,17 @@ services:
|
|||
ports:
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
# Persist encrypted configuration, state, and audit logs
|
||||
- ./dockflare_data:/app/data
|
||||
- dockflare_data:/app/data
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- DOCKER_HOST=tcp://docker-socket-proxy:2375
|
||||
depends_on:
|
||||
- redis
|
||||
docker-socket-proxy:
|
||||
condition: service_started
|
||||
dockflare-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_started
|
||||
networks:
|
||||
- cloudflare-net
|
||||
- dockflare-internal
|
||||
|
|
@ -107,7 +139,7 @@ services:
|
|||
restart: unless-stopped
|
||||
command: ["redis-server", "--save", "", "--appendonly", "no"]
|
||||
volumes:
|
||||
- ./dockflare_redis:/data
|
||||
- dockflare_redis:/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
|
|
@ -132,9 +164,9 @@ networks:
|
|||
|
||||
4. **For Existing Users**: If you are upgrading, DockFlare will detect your old `.env` file and automatically guide you through a quick migration process.
|
||||
|
||||
Redis runs on a private `dockflare-internal` network so only the DockFlare container can access it.
|
||||
The master now runs as the unprivileged `dockflare` user (UID/GID 65532) and only talks to Docker through the bundled socket proxy. If you bind-mount a host directory instead of using the named volume above, make sure it is writable by that UID/GID or adjust the `DOCKFLARE_UID`/`DOCKFLARE_GID` build args.
|
||||
|
||||
💡 *Need to manage workloads on additional hosts?* Deploy the [DockFlare Agent](https://github.com/ChrispyBacon-dev/DockFlare-Agent-prd) next to your containers, enrol it from the master UI, and let DockFlare orchestrate the tunnels for you. The agent image now runs as the non-root `dockflare` user (UID/GID 65532), so ensure any mounted directories are writable by that account or adjust the build-time `DOCKFLARE_UID/DOCKFLARE_GID` args. A full guide is available in the new [Multi-Server Agent](dockflare/app/templates/docs/Multi-Server-Agent.md) documentation.
|
||||
💡 *Need to manage workloads on additional hosts?* Deploy the [DockFlare Agent](https://github.com/ChrispyBacon-dev/DockFlare-Agent-prd) next to your containers, enrol it from the master UI, and let DockFlare orchestrate the tunnels for you. Both the master and agent images run as the non-root `dockflare` user by default, so align your volume permissions or override the build args if required. A full guide is available in the new [Multi-Server Agent](dockflare/app/templates/docs/Multi-Server-Agent.md) documentation.
|
||||
|
||||
</details>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,69 @@
|
|||
version: '3.8'
|
||||
services:
|
||||
docker-socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:v0.4.1
|
||||
container_name: docker-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- CONTAINERS=1
|
||||
- EVENTS=1
|
||||
- NETWORKS=1
|
||||
- IMAGES=1
|
||||
- POST=1
|
||||
- PING=1
|
||||
- INFO=1
|
||||
- EXEC=1
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
dockflare-init:
|
||||
image: alpine:3.20
|
||||
container_name: dockflare-init
|
||||
command: ["sh", "-c", "chown -R ${DOCKFLARE_UID:-65532}:${DOCKFLARE_GID:-65532} /app/data"]
|
||||
volumes:
|
||||
- dockflare_data:/app/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
restart: "no"
|
||||
|
||||
dockflare:
|
||||
#image: alplat/dockflare:stable # alplat/dockflare:unstable docker tag for beta versions
|
||||
build: ./dockflare # Uncomment to build from source instead
|
||||
build:
|
||||
context: ./dockflare
|
||||
args:
|
||||
DOCKFLARE_UID: ${DOCKFLARE_UID:-65532}
|
||||
DOCKFLARE_GID: ${DOCKFLARE_GID:-65532}
|
||||
container_name: dockflare
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5001:5000"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro # Required to monitor Docker events
|
||||
- dockflare_data:/app/data # Persistent storage for state
|
||||
- dockflare_data:/app/data
|
||||
networks:
|
||||
- cloudflare-net # Network for communication with other containers
|
||||
- cloudflare-net
|
||||
- dockflare-internal
|
||||
depends_on:
|
||||
- redis
|
||||
docker-socket-proxy:
|
||||
condition: service_started
|
||||
dockflare-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_started
|
||||
environment:
|
||||
- STATE_FILE_PATH=/app/data/state.json
|
||||
- TZ=Europe/Zurich # Set your timezone here
|
||||
- TZ=Europe/Zurich
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- CACHE_ENABLED=true
|
||||
- DNS_RECORDS_CACHE_TIMEOUT=300
|
||||
labels: # Optional
|
||||
- dockflare.enable=true
|
||||
- dockflare.hostname=master.dockflare.app
|
||||
- dockflare.service=http://host.docker.internal:5001
|
||||
- dockflare.access.policy=bypass
|
||||
- DOCKER_HOST=tcp://docker-socket-proxy:2375
|
||||
labels:
|
||||
- dockflare.enable=true
|
||||
- dockflare.hostname=master.dockflare.app
|
||||
- dockflare.service=http://host.docker.internal:5001
|
||||
- dockflare.access.policy=bypass
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: dockflare-redis
|
||||
|
|
@ -43,9 +81,10 @@ services:
|
|||
volumes:
|
||||
dockflare_data:
|
||||
redis-data:
|
||||
|
||||
networks:
|
||||
cloudflare-net:
|
||||
name: cloudflare-net
|
||||
external: true
|
||||
name: cloudflare-net
|
||||
external: true
|
||||
dockflare-internal:
|
||||
name: dockflare-internal
|
||||
|
|
|
|||
|
|
@ -32,19 +32,24 @@ RUN echo "DEBUG: Details of /usr/src/app/app/static AFTER npm run build:css:" &&
|
|||
RUN echo "DEBUG: Contents of /usr/src/app/app/static AFTER npm run build:css:" && ls -Alp /usr/src/app/app/static || echo "/usr/src/app/app/static NOT FOUND after build"
|
||||
RUN echo "DEBUG: Specifically checking for /usr/src/app/app/static/css/output.css AFTER npm run build:css:"
|
||||
RUN ls -l /usr/src/app/app/static/css/output.css || echo "/usr/src/app/app/static/css/output.css NOT FOUND after build"
|
||||
|
||||
FROM python:3.13-slim AS runtime
|
||||
ARG DOCKFLARE_UID=65532
|
||||
ARG DOCKFLARE_GID=65532
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
WORKDIR /app
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
wget \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends wget ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
RUN mkdir -p /app/static/css
|
||||
COPY --from=frontend-builder /usr/src/app/app/static/css/output.css /app/static/css/output.css
|
||||
COPY ./app /app
|
||||
RUN addgroup --system --gid ${DOCKFLARE_GID} dockflare \
|
||||
&& adduser --system --uid ${DOCKFLARE_UID} --ingroup dockflare dockflare \
|
||||
&& mkdir -p /app/data \
|
||||
&& chown -R dockflare:dockflare /app
|
||||
USER dockflare:dockflare
|
||||
ENV PYTHONPATH=/
|
||||
EXPOSE 5000
|
||||
CMD ["python", "main.py"]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,34 @@ Modify your `docker-compose.yml` file to include the `nginx` service. The key is
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
docker-socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:v0.4.1
|
||||
container_name: docker-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- CONTAINERS=1
|
||||
- EVENTS=1
|
||||
- NETWORKS=1
|
||||
- IMAGES=1
|
||||
- POST=1
|
||||
- PING=1
|
||||
- INFO=1
|
||||
- EXEC=1
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
dockflare-init:
|
||||
image: alpine:3.20
|
||||
command: ["sh", "-c", "chown -R 65532:65532 /app/data"]
|
||||
volumes:
|
||||
- dockflare_data:/app/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
restart: "no"
|
||||
|
||||
dockflare:
|
||||
image: alplat/dockflare:stable
|
||||
container_name: dockflare
|
||||
|
|
@ -28,12 +56,17 @@ services:
|
|||
ports:
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./dockflare_data:/app/data
|
||||
- dockflare_data:/app/data
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- DOCKER_HOST=tcp://docker-socket-proxy:2375
|
||||
depends_on:
|
||||
- redis
|
||||
docker-socket-proxy:
|
||||
condition: service_started
|
||||
dockflare-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_started
|
||||
networks:
|
||||
- cloudflare-net
|
||||
- dockflare-internal
|
||||
|
|
@ -44,9 +77,8 @@ services:
|
|||
container_name: my-nginx
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- cloudflare-net # Must be on the same network as DockFlare
|
||||
- cloudflare-net
|
||||
labels:
|
||||
# --- DockFlare Configuration ---
|
||||
- "dockflare.enable=true"
|
||||
- "dockflare.hostname=nginx.example.com"
|
||||
- "dockflare.service=http://nginx-webserver:80"
|
||||
|
|
@ -57,7 +89,7 @@ services:
|
|||
restart: unless-stopped
|
||||
command: ["redis-server", "--save", "", "--appendonly", "no"]
|
||||
volumes:
|
||||
- ./dockflare_redis:/data
|
||||
- dockflare_redis:/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
|
|
@ -72,7 +104,7 @@ networks:
|
|||
dockflare-internal:
|
||||
name: dockflare-internal
|
||||
```
|
||||
> **Why Redis?** DockFlare relies on Redis for caching, log streaming, and cross-thread messaging. Running it on a private `dockflare-internal` network keeps Redis reachable only by DockFlare while workloads stay on `cloudflare-net`.
|
||||
> **Why Redis?** DockFlare relies on Redis for caching, log streaming, and cross-thread messaging. Running it on the private `dockflare-internal` network keeps Redis reachable only by DockFlare, while workloads stay isolated on `cloudflare-net`.
|
||||
|
||||
|
||||
### 2. Understanding the Labels
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ This page lists some of the common issues that users may encounter and how to re
|
|||
2. **Look for Errors:** Look for any error messages. Common causes include:
|
||||
* An invalid `docker-compose.yml` file (e.g., incorrect syntax, volume mounting issues).
|
||||
* Problems with the Docker daemon itself.
|
||||
* Permission issues with the Docker socket (`/var/run/docker.sock`).
|
||||
* Connectivity or permission issues with the docker-socket-proxy service or the `DOCKER_HOST` setting.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +1,63 @@
|
|||
# Quick Start (Docker Compose)
|
||||
|
||||
This guide will walk you through the fastest way to get DockFlare up and running using Docker Compose.
|
||||
This guide walks through the fastest way to run DockFlare with the hardened socket proxy and rootless master configuration.
|
||||
|
||||
### 1. Create the `docker-compose.yml` file
|
||||
|
||||
First, create a `docker-compose.yml` file with the following content. This configuration uses the stable image of DockFlare, maps the required Docker socket, provisions Redis for caching/queueing, and sets up persistent volumes for both DockFlare and Redis.
|
||||
The stack below launches the docker-socket-proxy, primes the persistent volume with the correct ownership, and starts DockFlare alongside Redis.
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
docker-socket-proxy:
|
||||
image: tecnativa/docker-socket-proxy:v0.4.1
|
||||
container_name: docker-socket-proxy
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DOCKER_HOST=unix:///var/run/docker.sock
|
||||
- CONTAINERS=1
|
||||
- EVENTS=1
|
||||
- NETWORKS=1
|
||||
- IMAGES=1
|
||||
- POST=1
|
||||
- PING=1
|
||||
- INFO=1
|
||||
- EXEC=1
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
dockflare-init:
|
||||
image: alpine:3.20
|
||||
command: ["sh", "-c", "chown -R 65532:65532 /app/data"]
|
||||
volumes:
|
||||
- dockflare_data:/app/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
restart: "no"
|
||||
|
||||
dockflare:
|
||||
image: alplat/dockflare:stable
|
||||
container_name: dockflare
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5000:5000" # Exposes the web UI on the default port
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
# Mount the Docker socket (read-only)
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
# This volume is crucial for persisting your encrypted configuration
|
||||
- ./dockflare_data:/app/data
|
||||
- dockflare_data:/app/data
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379/0
|
||||
- DOCKER_HOST=tcp://docker-socket-proxy:2375
|
||||
depends_on:
|
||||
- redis
|
||||
docker-socket-proxy:
|
||||
condition: service_started
|
||||
dockflare-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_started
|
||||
networks:
|
||||
- cloudflare-net
|
||||
- dockflare-internal
|
||||
# Optional: publish the DockFlare UI itself via Cloudflare
|
||||
# labels:
|
||||
# - "dockflare.enable=true"
|
||||
# - "dockflare.hostname=dockflare.domain.tld"
|
||||
# - "dockflare.service=http://dockflare:5000"
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
|
|
@ -40,16 +65,14 @@ services:
|
|||
restart: unless-stopped
|
||||
command: ["redis-server", "--save", "", "--appendonly", "no"]
|
||||
volumes:
|
||||
- ./dockflare_redis:/data
|
||||
- dockflare_redis:/data
|
||||
networks:
|
||||
- dockflare-internal
|
||||
|
||||
# This volume stores your encrypted credentials and state
|
||||
volumes:
|
||||
dockflare_data:
|
||||
dockflare_redis:
|
||||
|
||||
# It is recommended to use an external network for your services
|
||||
networks:
|
||||
cloudflare-net:
|
||||
name: cloudflare-net
|
||||
|
|
@ -59,29 +82,31 @@ networks:
|
|||
```
|
||||
|
||||
**Notes:**
|
||||
- Before running the compose file, ensure the external network `cloudflare-net` exists: `docker network create cloudflare-net`.
|
||||
- The private `dockflare-internal` network isolates Redis so only the DockFlare container can access it, even if other services join `cloudflare-net`.
|
||||
- The master container runs as the `dockflare` user (UID/GID 65532). If you need to match different host permissions, set `DOCKFLARE_UID`/`DOCKFLARE_GID` and rebuild the image or adjust the init job.
|
||||
- The proxy is mandatory. DockFlare never mounts `/var/run/docker.sock` directly, which limits the Docker API surface the master can reach.
|
||||
- When using bind mounts instead of named volumes, make sure the target directory is writable by UID/GID 65532 (or your overridden values).
|
||||
- Create the external network once if it does not exist: `docker network create cloudflare-net`.
|
||||
|
||||
### 2. Run DockFlare
|
||||
|
||||
Once you have saved the `docker-compose.yml` file, you can start DockFlare with the following command:
|
||||
Start the stack in detached mode:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
This will pull the latest stable image and start the DockFlare container in the background.
|
||||
This brings up the proxy, primes the volume, and launches DockFlare together with Redis.
|
||||
|
||||
### 3. Complete the Pre-Flight Setup
|
||||
|
||||
After starting the container, open your web browser and navigate to `http://<your-server-ip>:5000`.
|
||||
After the services are running, open your browser to `http://<your-server-ip>:5000`.
|
||||
|
||||
You will be greeted by the **Pre-Flight Setup Wizard**. This one-time process will guide you through:
|
||||
1. Creating a password for the Web UI.
|
||||
2. Entering your Cloudflare credentials (Account ID, Zone ID, and API Token).
|
||||
3. Configuring your initial Cloudflare Tunnel.
|
||||
4. *(Optional)* Restoring from a full DockFlare backup archive. If you already have a `dockflare_backup_*.zip`, choose **Restore from backup** before Step 1—the wizard will import your configuration and automatically restart the container.
|
||||
The **Pre-Flight Setup Wizard** walks you through:
|
||||
1. Creating a password for the Web UI.
|
||||
2. Entering your Cloudflare credentials (Account ID, Zone ID, API Token).
|
||||
3. Configuring your initial Cloudflare Tunnel.
|
||||
4. *(Optional)* Restoring from a DockFlare backup archive. If you already have a `dockflare_backup_*.zip`, choose **Restore from backup** before Step 1; the wizard imports your configuration and restarts the container automatically.
|
||||
|
||||
### 4. For Existing Users (Upgrading)
|
||||
|
||||
If you are upgrading from an older version of DockFlare that used a `.env` file, DockFlare will automatically detect it. You will be guided through a simple migration process to import your existing settings and create a password for the new secure setup.
|
||||
If you are upgrading from an older release, DockFlare detects the legacy `.env` file, migrates your configuration into the encrypted store, and guides you through password creation. Keep the socket proxy in place—direct mounts of `/var/run/docker.sock` are no longer supported.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ This document explains how DockFlare secures both the Master node and enrolled A
|
|||
- **Cloudflare Tunnel Transport** – Agents expose no inbound ports. All traffic traverses the Cloudflare tunnel managed by the Master, reducing the attack surface on remote hosts.
|
||||
- **Authenticated Agent Calls** – Agent REST calls include their API key and are bound to their recorded agent ID. Token mismatches or revoked keys are rejected.
|
||||
- **Redis Backplane** – DockFlare relies on Redis for caching, log streaming, and cross-thread signalling. The recommended compose stack keeps Redis on a dedicated `dockflare-internal` network so workloads on `cloudflare-net` cannot reach it directly. Secure external Redis services with auth/TLS if you use them.
|
||||
- **Least-privilege runtime** – Agents run as the `dockflare` user (UID/GID 65532) inside the container and are designed to reach Docker through the bundled socket proxy so only inspection and lifecycle endpoints are exposed.
|
||||
- **Least-privilege runtime** – Both the master and agents run as the `dockflare` user (UID/GID 65532) and talk to Docker exclusively through the bundled socket proxy, keeping the exposed API surface minimal.
|
||||
|
||||
## 5. Authentication & Authorization
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ This document explains how DockFlare secures both the Master node and enrolled A
|
|||
|
||||
| Area | Recommendation |
|
||||
| --- | --- |
|
||||
| Docker Volumes | Persist `/app/data` (encrypted config, keys, state). Persist `/app/logs` if file logging is enabled. |
|
||||
| Docker Volumes | Persist `/app/data` (encrypted config, keys, state). Persist `/app/logs` if file logging is enabled, and ensure host mounts are writable by UID/GID 65532 or your overridden build args. |
|
||||
| Redis | Run `redis:7-alpine` alongside DockFlare on a private network (`dockflare-internal`) or point `REDIS_URL` to a hardened instance (auth/TLS). Avoid exposing Redis publicly. |
|
||||
| Backups | Download the `.zip` regularly and store it with `dockflare.key`. Both files are required to decrypt the configuration on restore. |
|
||||
| Agents | Treat API keys like credentials. Deploy them with the socket proxy so only required Docker endpoints are exposed, and remember the container runs as the unprivileged `dockflare` user (UID/GID 65532); align host permissions or rebuild with matching `DOCKFLARE_UID/DOCKFLARE_GID`. |
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{% extends "layout.html" %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}DockFlare is Restarting{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex flex-col items-center justify-center min-h-[60vh] text-center space-y-6">
|
||||
<img src="{{ url_for('static', filename='images/logo.svg') }}" alt="DockFlare Logo" class="w-24 h-24 animate-pulse" />
|
||||
<img src="{{ url_for('static', filename='images/logo.gif') }}" alt="DockFlare Logo" class="w-24 h-24 animate-pulse" />
|
||||
<div class="space-y-2">
|
||||
<h1 class="text-3xl font-semibold">Hold tight, DockFlare is rebooting...</h1>
|
||||
<p class="text-lg opacity-80">We’re loading your restored configuration and giving the tunnel hamsters a quick pep talk.</p>
|
||||
|
|
@ -23,14 +23,33 @@
|
|||
<script>
|
||||
(function() {
|
||||
const seconds = {{ countdown_seconds }};
|
||||
const redirectUrl = "{{ url_for('auth.login') }}";
|
||||
const pingUrl = "{{ url_for('web.ping') }}";
|
||||
const countdownEl = document.getElementById('countdown');
|
||||
const progressEl = document.getElementById('progress');
|
||||
let remaining = seconds;
|
||||
|
||||
const pollForReady = () => {
|
||||
fetch(pingUrl, { cache: 'no-store' })
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
window.location.replace(redirectUrl);
|
||||
return;
|
||||
}
|
||||
setTimeout(pollForReady, 1000);
|
||||
})
|
||||
.catch(() => {
|
||||
setTimeout(pollForReady, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
const tick = () => {
|
||||
remaining -= 1;
|
||||
if (remaining < 0) {
|
||||
window.location.reload();
|
||||
clearInterval(timerId);
|
||||
countdownEl.textContent = 0;
|
||||
progressEl.value = seconds;
|
||||
pollForReady();
|
||||
return;
|
||||
}
|
||||
countdownEl.textContent = remaining;
|
||||
|
|
@ -40,7 +59,7 @@
|
|||
countdownEl.textContent = seconds;
|
||||
progressEl.setAttribute('max', seconds);
|
||||
progressEl.value = 0;
|
||||
setInterval(tick, 1000);
|
||||
const timerId = setInterval(tick, 1000);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ def restore_from_backup():
|
|||
current_app.import_from_env = False
|
||||
|
||||
if is_full_archive:
|
||||
return render_template('restore_restarting.html', countdown_seconds=5)
|
||||
return render_template('restore_restarting.html', countdown_seconds=7)
|
||||
|
||||
return redirect(url_for('auth.login'))
|
||||
except Exception as err:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue