Installation
This quickstart gets a new Safe Harbor instance running from the published container images. It is written for a single Docker host and uses the default Compose file in the repository.
The default first-run path is intentionally local: the app listens on
http://localhost:8000/, uses the development configuration from the Compose
file, and creates the first administrator through the browser setup flow.
Review Configuration before publishing the service beyond the
host.
1. Prerequisites
Install these tools on the host before cloning Safe Harbor:
- Docker Engine 24 or newer
- Docker Compose v2
- Git
Use a host with at least:
- 2 GB RAM
- 10 GB free disk space
Supported host platforms:
- Linux
- macOS
- Windows through WSL2
If you expose Safe Harbor directly with a reverse proxy instead of Cloudflare
Tunnel, make sure inbound ports 80 and 443 are open on the host firewall
and reachable from the internet. The default local quickstart does not need
those public ports.
Confirm Docker and Compose are available:
docker --version
docker compose version
Confirm the Docker daemon is running:
docker info
If docker info fails, start Docker Desktop on macOS or Windows, or start the
Docker service on Linux before continuing.
2. Clone the repo
Clone Safe Harbor and enter the repository:
git clone https://github.com/danner26/Safe-Harbor.git
cd Safe-Harbor
The commands in the rest of this guide assume your shell is in the repository
root, next to docker-compose.yml and .env.example.
3. Configure .env
Create the local environment file:
cp .env.example .env
Open .env in your editor and review the minimum first-run settings:
FLASK_CONFIG=development
SECRET_KEY=change-me-in-prod
TRUST_PROXY_HEADERS=0
SAFEHARBOR_VERSION=
SERVER_NAME=
Set SECRET_KEY before using the app. Use a long random value:
openssl rand -hex 32
Replace the placeholder in .env:
SECRET_KEY=paste-a-random-value-here
Decide whether Safe Harbor should trust reverse-proxy headers:
TRUST_PROXY_HEADERS=0
Use TRUST_PROXY_HEADERS=0 for the local quickstart, where no trusted proxy is
in front of the app. After setting up Cloudflare Tunnel, Caddy, nginx, or
another trusted reverse proxy, flip this to TRUST_PROXY_HEADERS=1; see
Cloudflare Tunnel for the public-access path.
Leave SAFEHARBOR_VERSION blank for the latest published image:
SAFEHARBOR_VERSION=
For a stable install, pin a published image tag:
SAFEHARBOR_VERSION=1.0.0
Set SERVER_NAME only when Safe Harbor needs to send email links, such as
password reset links generated outside a web request:
SERVER_NAME=safeharbor.example.com
PREFERRED_URL_SCHEME=https
Leave SERVER_NAME blank for a local first run:
SERVER_NAME=
The default Compose stack runs FLASK_CONFIG=development for the first-run
setup flow. If you run Safe Harbor with FLASK_CONFIG=production, set
SECRET_KEY first, then pass FLASK_CONFIG=production through your Compose
override or deployment environment after reviewing Configuration.
4. Pull + start
Pull the configured images:
docker compose pull
Create the host backup directory and assign ownership compatible with the containers:
mkdir -p backups && sudo chown -R 1000:1000 backups
Safe Harbor bind-mounts ./backups into the web and backups containers. The
container process writes as UID 1000, so the host directory must be writable
by that UID before backups or restore exports can be created there.
Start the default stack:
docker compose up -d
The default stack starts the web app, Postgres, Redis, and the background worker. Wait about 30 seconds while the entrypoint applies migrations and seeds initial data.
Check container status:
docker compose ps
Check the app health endpoint:
curl -fsS http://localhost:8000/healthz
If the health check fails during the first few seconds, inspect logs and retry:
docker compose logs --tail=100 web
curl -fsS http://localhost:8000/healthz
The cloudflared service does not start by default. To run the Compose-managed
Cloudflare Tunnel sidecar, set a tunnel token and opt in to the tunnel
profile:
TUNNEL_TOKEN=your-cloudflare-tunnel-token
COMPOSE_PROFILES=tunnel
Then start with the same Compose command:
docker compose up -d
Use COMPOSE_PROFILES=tunnel,backup only when you want both the tunnel sidecar
and scheduled backup services.
5. First login
Open the local app:
http://localhost:8000/
On a new install, Safe Harbor redirects to /setup. Enter the administrator
email address and password, submit the setup form, then sign in with that
administrator account.
For a headless or scripted install, create the administrator from the running web container instead:
docker compose exec web flask --app safeharbor.wsgi:app safeharbor create-admin
Follow the prompts for the admin email address and password. After the command
finishes, visit http://localhost:8000/ and sign in.
If the setup page does not load, or the CLI reports that the web service is not running, use Troubleshooting to check Compose status, container logs, database connectivity, and health checks.
Optional: Cloudflare Tunnel
Cloudflare Tunnel is the recommended path for publishing Safe Harbor without opening inbound ports on a home or small-office network. Start with the local install above. After reviewing Deployment, configure tunnel setup and reverse-proxy details for your environment.
Optional: Backups
Backups are opt-in. After the app is running, review Backups to enable scheduled backups, choose retention settings, and confirm the backup tarballs include both database data and uploaded files.
Optional: Troubleshooting
For startup failures, unhealthy containers, setup problems, email issues, or
proxy routing problems, use Troubleshooting. Include
docker compose ps, recent web logs, and the failing command output when
diagnosing an install.