
Run an AI agent orchestration workspace on your own infrastructure, verify it locally, and expose only the HTTP access you intend to use
EpicStaff is a source-available, self-hosted platform for building AI agent flows through a visual editor backed by Django. In this guide, we install the documented Docker Compose deployment on Windows, macOS, or Linux, generate its required signing keys, start the stack, and verify the browser interface at its documented local URL. Once the local deployment works, we explain how to connect it to a Localtonet HTTP tunnel so authorized remote users or webhook senders can reach the application without inbound router port forwarding, firewall changes, VPN setup, or a public IP address. We also cover lifecycle management, security boundaries, webhook URL planning, and common troubleshooting checks.
๐ What's in this guide
What you are deploying
EpicStaff is designed for self-hosted AI agent orchestration and workflow automation. Its visual editor lets users construct and inspect agent flows, while its Django backend handles the application logic. The project describes support for custom Python logic, persistent agent context backed by Redis and PostgreSQL, application state, and integrations through mechanisms such as MCP and Python.
This installation guide follows the project's documented Docker Compose quick start. Docker runs the application and its supporting services as a coordinated stack. Named Docker volumes preserve the data expected by the deployment, while an external Docker network named mcp-network supports network connectivity expected by the Compose configuration. A host directory under the current user's home directory is configured for saved files.
The repository describes EpicStaff as source-available rather than explicitly open-source. Source availability and open-source licensing are not interchangeable terms. Review the repository's current license before adopting, modifying, redistributing, or using the software in a particular commercial environment.
http://localhost. Local verification should always happen before remote access is introduced.
Local access and remote access are separate stages
The most reliable deployment sequence is to treat installation and remote connectivity as two different tasks. First, EpicStaff must start successfully and respond at its local URL. Only after that should a tunnel be added. If the application is not healthy locally, a public URL cannot correct the underlying container, configuration, storage, or application error.
When remote access is added, the Localtonet client runs on the EpicStaff host or another device capable of reaching the local web service. The client connects outward to our relay infrastructure. The resulting public HTTPS address forwards HTTP traffic to the configured local IP address and port while the selected device remains connected and the tunnel remains running.
| Layer | Purpose | How to verify it |
|---|---|---|
| EpicStaff containers | Run the application and supporting services | Inspect Compose status and logs |
| Local HTTP endpoint | Serve the browser interface on the host | Open http://localhost on the EpicStaff host |
| Localtonet client | Establish an outbound relay connection | Confirm that the selected device is connected |
| HTTP tunnel | Forward the public HTTP request to EpicStaff | Start the tunnel and test its assigned public URL |
| EpicStaff webhook route | Receive an HTTP event at an application-defined path | Send a controlled test event and confirm expected processing |
Prerequisites for the Docker Compose installation
The official EpicStaff quick start requires Git and Docker Desktop. Git downloads the repository, while Docker Desktop supplies the container runtime and Compose tooling used by the documented commands. The quick start provides command blocks for Windows PowerShell, macOS Terminal, and Linux Terminal.
Before running the installation, confirm that Git and Docker are available in the shell you intend to use. Docker Desktop must be running, not merely installed. The host also needs sufficient free storage for container images, named volumes, application data, and the saved-files directory. Exact CPU, memory, and disk minimums are not established by the supplied project evidence, so this guide does not invent fixed sizing requirements.
You should also decide which host account will own the deployment. The documented setup maps CREW_SAVEFILES_PATH to a savefiles directory under that account's home directory. Running the command later from another account changes the meaning of the home-directory variable and may lead to a different host path than expected.
EpicStaff requires both SECRET_KEY and JWT_SECRET, and the stack refuses to start without them. The documented commands generate independent values and write them to src/.env. Keep that file private, do not commit it, and do not paste its contents into support messages, screenshots, logs, or tunnel configuration.
What the setup creates
The quick start clones the repository, copies src/.env.example to src/.env, adjusts the saved-files path, and generates the two required signing values. It then creates five named Docker volumes and the external mcp-network network before starting a build through Docker Compose.
| Resource | Type | Operational significance |
|---|---|---|
sandbox_venvs |
Docker volume | Persistent resource required by the documented stack |
crew_pgdata |
Docker volume | Persistent PostgreSQL-related data resource |
graph_data |
Docker volume | Persistent graph-related data resource |
crew_config |
Docker volume | Persistent configuration resource |
media_data |
Docker volume | Persistent media-related resource |
mcp-network |
Docker network | External network expected by the deployment |
$HOME/savefiles |
Host directory on macOS and Linux | Host-side saved-files path written into the environment configuration |
$HOME\savefiles semantics through PowerShell |
Host directory on Windows | Home-based saved-files path inserted by the PowerShell setup |
Named volumes are deliberately outside the lifecycle of an individual container. Rebuilding or replacing containers does not automatically mean that their named-volume data disappears. Conversely, explicitly deleting volumes can remove persistent data. Treat volume-removal commands as destructive and create an appropriate backup before making storage changes.
Install EpicStaff with Docker Compose

The EpicStaff quick start presents the installation as two official steps: install the required tools, then run the operating-system-specific download and setup command. The command blocks below preserve that documented sequence.
Install Git and Docker Desktop
Install Git so the repository can be cloned, and install and start Docker Desktop so the containers can be built and run. Use PowerShell on Windows or a terminal on macOS and Linux.
Download, configure, and start EpicStaff
Run the complete command block for your operating system. It clones the main repository, creates src/.env, configures the saved-files path, generates SECRET_KEY and JWT_SECRET, creates the required Docker resources, and starts the Compose build.
Windows installation with PowerShell
Open PowerShell as the user who will own the deployment, then run the documented block:
git clone https://github.com/EpicStaff/EpicStaff.git; cd EpicStaff/src; Copy-Item .env.example .env; $savefiles = "$HOME/savefiles"; $file = ".env"; $key = { -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 60 | % {[char]$_}) }; (Get-Content $file) -replace "CREW_SAVEFILES_PATH=/c/savefiles", "CREW_SAVEFILES_PATH=$savefiles" -replace "^SECRET_KEY=.*", "SECRET_KEY=$(& $key)" -replace "^JWT_SECRET=.*", "JWT_SECRET=$(& $key)" | Set-Content $file; docker volume create sandbox_venvs; docker volume create crew_pgdata; docker volume create graph_data; docker volume create crew_config; docker volume create media_data; docker network create mcp-network; docker-compose up --build
This command enters EpicStaff/src immediately after cloning. The environment template is therefore copied from the current directory, and Docker Compose is started from the directory containing the deployment configuration.
macOS installation
Open Terminal and run the documented macOS block:
git clone -b main https://github.com/EpicStaff/EpicStaff.git && cd EpicStaff && cp src/.env.example src/.env && savefiles="$HOME/savefiles" && sed -i '' "s|CREW_SAVEFILES_PATH=/c/savefiles|CREW_SAVEFILES_PATH=$savefiles|" src/.env && sed -i '' "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -base64 48 | tr -d '=+/')|" src/.env && sed -i '' "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -base64 48 | tr -d '=+/')|" src/.env && docker volume create sandbox_venvs && docker volume create crew_pgdata && docker volume create graph_data && docker volume create crew_config && docker volume create media_data && docker network create mcp-network && cd src && docker-compose up --build
The macOS form uses the BSD-compatible sed -i '' syntax and OpenSSL to generate each signing value. It enters the repository root first, edits src/.env, and then enters src before starting Compose.
Linux installation
Open a terminal and run the documented Linux block:
git clone -b main https://github.com/EpicStaff/EpicStaff.git && cd EpicStaff && cp src/.env.example src/.env && savefiles="$HOME/savefiles" && sed -i "s|CREW_SAVEFILES_PATH=/c/savefiles|CREW_SAVEFILES_PATH=$savefiles|" src/.env && sed -i "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -base64 48 | tr -d '=+/')|" src/.env && sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -base64 48 | tr -d '=+/')|" src/.env && docker volume create sandbox_venvs && docker volume create crew_pgdata && docker volume create graph_data && docker volume create crew_config && docker volume create media_data && docker network create mcp-network && cd src && docker-compose up --build
The Linux command follows the same deployment sequence as the macOS command but uses the applicable GNU-style sed -i form.
Generate SECRET_KEY and JWT_SECRET once and retain them securely. Changing them later signs out every user. Back up the environment configuration through a secure secrets-management process, but never store it in a public repository or expose it through the EpicStaff web root.
About the first build
The final docker-compose up --build operation builds the required images and starts the stack in the foreground. The terminal remains attached to container output. Build duration depends on the host, network connection, image cache, and current project dependencies, so no universal completion time should be assumed.
Keep the terminal visible during the initial startup. A container can be created successfully while its application later reports a configuration or dependency error. Wait until the stack settles, review the output for repeating failures, and then perform the browser test.
Verify EpicStaff locally before creating a tunnel

Once the stack is running, open the documented endpoint on the EpicStaff host:
http://localhost
A successful test should return the EpicStaff web interface rather than a browser connection error, an unrelated service, or an infrastructure error page. Complete any first-run workflow presented by the installed version, then confirm that the interface remains responsive across more than one request.
The available evidence establishes http://localhost as the local URL, but it does not explicitly state a numeric host port. This distinction matters because the Localtonet HTTP tunnel configuration needs the actual local IP address and port. Do not guess a port solely from a container's internal port or from an example written for another release.
From the EpicStaff/src directory, inspect the running Compose project and its published port mapping:
docker-compose ps
Use the host-side published port shown by the active deployment. Container-only ports are not automatically reachable from the host. If your Docker installation uses the newer space-separated Compose command, its equivalent status command may be docker compose ps, but the EpicStaff quick start itself currently uses docker-compose.
A tunnel forwards requests to a local target. It does not start stopped containers, repair an invalid environment file, create missing Docker resources, or make an unhealthy application healthy. If http://localhost does not work on the host, resolve that problem before testing the public URL.
Verify the address from the future tunnel host
If the Localtonet client will run directly on the EpicStaff machine, a loopback target can be appropriate because the client and web service share a network namespace at the host level. If the client will run on another machine, localhost on that second machine refers to the second machine itself, not to the EpicStaff host. In that arrangement, the client device must be able to reach EpicStaff through an actual LAN address and the published host port.
Test the precise address from the same device that will run our client. This avoids a common situation where EpicStaff works in a browser on its own host but is unreachable from a separate tunnel device because of host binding, local firewall policy, routing, or network segmentation.
Operate and maintain the EpicStaff stack
The initial command runs Compose in the foreground. Stopping that attached process normally stops the running Compose session. For later starts, return to the EpicStaff/src directory and use the same Compose configuration and command style supported by the installation.
Useful Compose-level checks include:
docker-compose ps
docker-compose logs
The status output shows whether services are running, stopped, restarting, or exposing host mappings. Logs provide application and infrastructure details without requiring guessed service names. When investigating an issue, start with the complete stack output before narrowing the command to a specific service.
To stop and remove the Compose-managed containers and network resources defined by the project while retaining named volumes, the conventional project command is:
docker-compose down
Do not add volume-removal options unless you have reviewed their consequences and have a verified backup. The five named volumes were created to persist deployment data outside individual containers.
Updating the source
Before updating, review the release notes and upgrade guidance for the version you intend to install. Preserve a secure copy of src/.env and back up relevant persistent data. Do not blindly rerun the original setup block over an existing installation because it copies the environment template and generates signing keys. Replacing the existing signing values would invalidate user sessions.
After updating the repository through an upgrade process appropriate to the chosen release, rebuild and restart the stack according to the current EpicStaff instructions. Verify local access again before restarting public access. This local-first check prevents an application upgrade problem from being misdiagnosed as a tunneling problem.
Alternative deployment modes
EpicStaff also provides separate instructions for a partly local development setup and for Podman. The partly local mode runs selected services locally while keeping other components in containers, which can be useful for controlled development and testing. Podman has its own setup path. This article intentionally documents the primary Docker Compose quick start, so Docker-specific commands should not be copied into an alternative deployment without checking that deployment's instructions.
Make the EpicStaff web UI remotely reachable with Localtonet
After the local interface works and the actual host port has been confirmed, an HTTP tunnel can publish the service through Localtonet. Our client establishes an outbound connection to a relay server. This means you do not need an inbound router port-forwarding rule, firewall changes, a VPN setup, or a public IP address for this workflow.
HTTP tunnels point to a local IP address and port on, or reachable from, the client device. HTTP process types can use a random subdomain, a supported custom subdomain, or a custom domain, and they serve the target at a public HTTPS address. Availability and configuration details can vary, so obtain the current server choices and options from the dashboard rather than copying a hardcoded region or server code from an article.
Install and run our client
Install the Localtonet client on the EpicStaff host or on another device that can reach the verified EpicStaff HTTP endpoint. Keep the client running for as long as remote access is required.
Authenticate or select the client device
Use the device-specific authentication token associated with the client that will carry the tunnel. Never guess, publish, or embed the token in an article, script, webhook URL, or source repository.
Select an available relay server
Choose a currently available relay server or region from the product interface. Do not hardcode a server code because available values can change and may vary by deployment or plan.
Create the HTTP tunnel configuration
Choose an HTTP tunnel and enter the local IP address and the verified host-side port for EpicStaff. If our client runs on the same host, use the address that successfully reaches the local service there. If it runs elsewhere, use an address reachable from that client device.
Start the tunnel and test the assigned URL
Creating a tunnel does not make it run. Press Start, then open the assigned public URL from a separate network or browser session and confirm that the expected EpicStaff interface responds.
Stop or delete access when it is no longer needed
Stop the tunnel to end remote forwarding while retaining its configuration, or delete it when the configuration is no longer required. The public endpoint is available only while the selected client is connected and the tunnel is running.
Local success at localhost limits access to the machine by default. Starting an HTTP tunnel creates an internet-reachable entry point. Confirm EpicStaff's authentication and authorization configuration, use least-privilege accounts, and expose only the routes and environment intended for remote use. Never treat an unguessable URL as a substitute for authentication.
Choosing the correct target
The target must be the host-side endpoint, not an arbitrary container address copied from Docker's internal network. Container addresses can be ephemeral and may not be reachable by a client running directly on the host. Use the published mapping reported by the running Compose deployment and verify that exact target from the Localtonet client device.
If the tunnel returns a gateway-style error while the local browser works, compare the two paths carefully. The browser may be using localhost on the EpicStaff host while our client is running on another computer. It may also be targeting a different port from the one published by Compose.
Use the public HTTP origin for EpicStaff webhook delivery

A webhook sender must be able to reach the receiving application over the network. A service bound only to a local machine cannot normally receive requests from an internet-hosted system. Once the EpicStaff HTTP service is available through a running Localtonet HTTP tunnel, the assigned public HTTPS origin can be combined with the exact webhook path configured or documented in your EpicStaff flow.
The supplied project evidence does not establish a universal EpicStaff webhook path, request method, payload schema, authentication header, or response contract. Those details can depend on the installed release and the flow being configured. For that reason, this guide does not invent an endpoint such as /webhook or assume that every request should use POST.
Build the destination only after EpicStaff provides or you configure the actual route:
https://your-assigned-public-host.example/<exact-epicstaff-webhook-path>
The hostname above is intentionally illustrative rather than a real Localtonet address. Use the public URL assigned to your running tunnel, then append only the path required by the relevant EpicStaff workflow.
A safe webhook test sequence
First, verify that the EpicStaff interface works locally. Second, start the HTTP tunnel and verify the public origin in a browser. Third, confirm the exact application route and expected request format. Fourth, send a controlled event that cannot trigger an irreversible production action. Finally, inspect EpicStaff's behavior and the webhook sender's delivery result.
Keep diagnostic layers separate. A DNS or connection failure points toward public reachability or tunnel state. A tunnel connection that reaches the wrong local service points toward the target address or port. An HTTP 404 response commonly indicates that the application was reached but the path is not present. An authorization response indicates that network delivery occurred but application-level credentials or permissions were not accepted.
URLs may appear in browser history, application logs, provider dashboards, and diagnostic output. Prefer the authentication and signature mechanism documented by the receiving workflow and webhook sender. Redact credentials before sharing request details.
Security and exposure checklist
Self-hosting gives you control over the deployment boundary, but it also makes configuration, patching, access control, backups, and monitoring your responsibility. A tunnel solves connectivity. It does not replace application authorization, secret management, host hardening, or workflow-level safeguards.
| Control | Risk addressed | Recommended practice |
|---|---|---|
| Signing-key protection | Session compromise or forced sign-outs | Keep src/.env private and preserve stable generated values |
| Application authentication | Unauthorized use of the public UI | Require appropriate EpicStaff accounts, roles, and permissions |
| Webhook verification | Forged event delivery | Validate supported signatures, tokens, or sender credentials |
| Least privilege | Excessive impact from a compromised account or flow | Grant only the permissions required for the intended operation |
| Tunnel lifecycle | Unnecessary continuing exposure | Stop or delete the tunnel when remote access is not needed |
| Version maintenance | Known application or dependency vulnerabilities | Review releases, back up data, and test updates locally |
| Persistent-data backups | Loss caused by host failure or destructive maintenance | Back up the relevant volumes, configuration, and host files securely |
Protect the Localtonet device token as a credential. It identifies the client device that runs the tunnel and must not be placed in public configuration examples. Likewise, obtain relay server selections from the current dashboard rather than distributing hardcoded server values.
Consider separating development and production deployments. A flow that executes Python logic or connects to internal systems can have effects beyond the web interface itself. Review permissions on connected services, restrict credentials to the minimum scope, and use non-production resources during initial remote and webhook testing.
Troubleshoot installation and remote-access problems
The setup stops before Compose starts
On macOS and Linux, the setup uses &&, so one failed operation prevents later operations from running. Check the first reported error rather than focusing only on the missing web page. Common categories include an unavailable command, a failed repository clone, an environment-file edit failure, Docker not running, or a resource name that already exists.
If some volumes or mcp-network were created during an earlier attempt, inspect the existing Docker resources before deleting anything. Existing named volumes may contain data from a prior deployment. Once the prerequisite state is understood, run the remaining documented operations from the correct directory rather than regenerating signing secrets unnecessarily.
EpicStaff reports missing signing keys
Confirm that src/.env exists and that both SECRET_KEY and JWT_SECRET received generated values. Do not paste those values into terminal transcripts or support requests. If the file was created but the substitutions failed, diagnose the operating-system-specific shell command and file location.
http://localhost does not open
Keep the tunnel stopped and inspect the Compose status and logs:
docker-compose ps
docker-compose logs
Confirm that the stack is still running, that no required container is repeatedly restarting, and that a host port is published. Also confirm that the browser test is performed on the EpicStaff host. On another computer, localhost refers to that other computer.
The public URL does not respond
Confirm all lifecycle requirements: our client must be connected, the correct device must be selected, and the tunnel must have been started. Creating the configuration alone is not sufficient. Then verify the local target from the client device, including the actual published host port.
The public URL reaches the wrong application
This usually means the configured target port belongs to another local service. Recheck the active Compose mapping rather than assuming a default numeric port. If multiple development applications are running on the same host, identify the host-side mapping associated with EpicStaff.
The web UI loads but a webhook fails
A working home page proves that the public origin reaches the web application, but it does not prove that a particular webhook path exists or accepts the supplied request. Check the exact route, request method, content type, payload schema, authentication mechanism, and installed EpicStaff version. An application response such as 404, 401, 403, or 405 is different from a network connection failure and should be investigated at the application or integration layer.
The tunnel worked and later became unavailable
Check whether the Localtonet client is still running and connected, whether the tunnel is still in the running state, and whether the EpicStaff containers remain healthy. The public endpoint is available only while the selected client is connected and the tunnel is running. Host restarts, client shutdowns, stopped Compose sessions, and changed local mappings can all interrupt the complete request path.
Frequently asked questions
Is EpicStaff open-source?
EpicStaff describes its deployment as source-available. This guide does not relabel it as open-source. Review the current repository license to understand the permissions and restrictions that apply to your intended use.
What local port does EpicStaff use?
The verified project instructions identify http://localhost as the local endpoint but do not explicitly state a numeric host port. Inspect the published mapping of your running Compose deployment and use its host-side port. Do not guess from a container-only port.
Does Localtonet require router port forwarding for this setup?
No. Our client establishes an outbound connection to a Localtonet relay server, so this workflow does not require inbound router port forwarding, firewall changes, VPN setup, or a public IP address.
Can the Localtonet client run on a different device from EpicStaff?
Yes, provided that the client device can reach EpicStaff over the local network. In that arrangement, do not configure localhost as the target because it would refer to the client device. Use the reachable address and verified published port of the EpicStaff host.
Does creating an HTTP tunnel immediately make EpicStaff public?
No. Creating the tunnel saves its configuration, but the tunnel must also be started. It remains available only while the selected client device is connected and the tunnel is running.
What happens if I change SECRET_KEY or JWT_SECRET?
The project states that changing these signing keys signs out every user. Generate each key once, store the environment file securely, and avoid rerunning setup actions that overwrite the existing values during routine updates.
Can one HTTP tunnel serve both the EpicStaff UI and webhook routes?
An HTTP tunnel forwards requests for its public origin to the configured local HTTP service, so application routes under that service can be reachable through the same origin. Whether a particular EpicStaff webhook route exists, and what authentication or payload it requires, depends on the installed version and configured workflow. Verify the exact route rather than inventing one.
Is the public URL enough to secure EpicStaff?
No. Treat the URL as an address, not an authorization control. Configure appropriate EpicStaff authentication and permissions, validate webhook senders where supported, protect all secrets, apply least privilege, maintain the host, and stop the tunnel when public access is not required.
Connect your verified EpicStaff deployment with Localtonet
Once EpicStaff responds locally and you have confirmed its actual host-side port, create an HTTP tunnel to provide controlled remote browser and webhook reachability without configuring inbound router port forwarding.
Get Started Free โ