> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spoo.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Local Development Setup

> Set up spoo.me for local development with Docker or manual installation

## Docker Setup (Recommended)

One command sets up MongoDB, Redis, and the app with hot-reloading:

```bash theme={null}
git clone https://github.com/spoo-me/spoo.git
cd spoo
cp .env.example .env
docker compose up -d
```

Visit [http://localhost:8000](http://localhost:8000). The app auto-reloads on file changes via the volume mount.

```bash theme={null}
docker compose logs -f app   # View logs
docker compose down           # Stop everything
```

<Info>
  The `.env.example` file comes pre-configured for local development — MongoDB and Redis connect to the Docker containers automatically. Auth features (OAuth, email) are disabled by default and work fine without configuration.
</Info>

### Running Tests and Linting

You'll need `uv` for running tests and linting outside the container:

```bash theme={null}
pip install uv
uv sync
uv run pre-commit install     # Auto-lint on every commit
uv run pytest                  # Run test suite
```

### Configuring Optional Features

The default `.env.example` gets you a working instance for URL shortening, redirects, and analytics. For additional features, configure these in your `.env`:

| Feature               | Env Vars                                                 | Setup Guide                                                                   |
| --------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------- |
| **JWT Auth (RSA)**    | `JWT_PRIVATE_KEY`, `JWT_PUBLIC_KEY`                      | [Authentication Setup](/self-hosting/setting-up-authentication)               |
| **JWT Auth (HMAC)**   | `JWT_SECRET`                                             | Generate with `python -c "import os; print(os.urandom(32).hex())"`            |
| **Google OAuth**      | `GOOGLE_OAUTH_CLIENT_ID`, `GOOGLE_OAUTH_CLIENT_SECRET`   | [Authentication Setup](/self-hosting/setting-up-authentication#google-oauth)  |
| **GitHub OAuth**      | `GITHUB_OAUTH_CLIENT_ID`, `GITHUB_OAUTH_CLIENT_SECRET`   | [Authentication Setup](/self-hosting/setting-up-authentication#github-oauth)  |
| **Discord OAuth**     | `DISCORD_OAUTH_CLIENT_ID`, `DISCORD_OAUTH_CLIENT_SECRET` | [Authentication Setup](/self-hosting/setting-up-authentication#discord-oauth) |
| **Email (Zeptomail)** | `ZEPTO_API_TOKEN`, `ZEPTO_FROM_EMAIL`                    | See `.env.example` comments                                                   |
| **Sentry**            | `SENTRY_DSN`                                             | Leave empty to disable                                                        |
| **Discord Webhooks**  | `CONTACT_WEBHOOK`, `URL_REPORT_WEBHOOK`                  | [Creating Webhooks](/self-hosting/creating-discord-webhooks)                  |
| **hCaptcha**          | `HCAPTCHA_SECRET`                                        | [hcaptcha.com](https://www.hcaptcha.com/)                                     |

<Tip>
  All optional features degrade gracefully — the app runs fine with empty values. Configure only what you need.
</Tip>

## Manual Setup (Without Docker)

If you prefer not to use Docker, you'll need to install MongoDB and Redis yourself.

### Prerequisites

* Python 3.10+
* [uv](https://docs.astral.sh/uv/) package manager
* MongoDB 7.0+ ([setup guide](/self-hosting/setting-up-mongo))
* Redis 7.0+ ([setup guide](/self-hosting/setting-up-redis))

### Installation

```bash theme={null}
git clone https://github.com/spoo-me/spoo.git
cd spoo

# Install dependencies
pip install uv
uv sync
uv run pre-commit install

# Configure environment
cp .env.example .env
```

Edit `.env` to point to your local MongoDB and Redis:

```bash theme={null}
MONGODB_URI=mongodb://localhost:27017/
REDIS_URI=redis://localhost:6379
```

### Running the Server

```bash theme={null}
uv run uvicorn main:app --host 0.0.0.0 --port 8000 --reload
```

Visit [http://localhost:8000](http://localhost:8000). Check [http://localhost:8000/health](http://localhost:8000/health) to verify MongoDB and Redis are connected.

## Verifying Your Setup

After starting the app (via Docker or manually):

1. **Health check**: `curl http://localhost:8000/health` — should return `{"status": "healthy"}`
2. **Shorten a URL**: Visit the homepage and create a test short link
3. **Test redirect**: Click the short link to verify it redirects
4. **Run tests**: `uv run pytest` — all tests should pass

## Troubleshooting

<AccordionGroup>
  <Accordion title="Docker: Port 8000 already in use">
    ```bash theme={null}
    # Find what's using port 8000
    lsof -i :8000    # macOS/Linux
    netstat -ano | findstr :8000  # Windows

    # Or change the port in docker-compose.yml
    ports:
      - "8001:8000"
    ```
  </Accordion>

  <Accordion title="Docker: App can't connect to MongoDB">
    Check that all containers are running:

    ```bash theme={null}
    docker compose ps
    ```

    If the `db` container is unhealthy, check its logs:

    ```bash theme={null}
    docker compose logs db
    ```
  </Accordion>

  <Accordion title="Manual: ModuleNotFoundError">
    Make sure you're using `uv run` to execute commands — it activates the virtual environment automatically:

    ```bash theme={null}
    uv run uvicorn main:app --reload   # correct
    uvicorn main:app --reload           # may fail if venv not activated
    ```
  </Accordion>

  <Accordion title="Health endpoint shows 'degraded'">
    This means MongoDB is connected but Redis isn't. The app still works — Redis is optional for caching. Check your `REDIS_URI` in `.env` or verify Redis is running.
  </Accordion>
</AccordionGroup>
