## Running using Docker

Spothole comes with a Docker configuration to make it easy to run it in a containerised environment. To set it up using
Docker, the easiest way is to use a Docker Compose file. Create a new directory such as `/opt/docker/spothole` and
create a `compose.yaml` file inside it with the following contents:

```yaml
services:
  spothole:
    container_name: spothole
    build:
      context: https://git.ianrenton.com/ian/spothole.git#main
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config.yml:/app/config.yml
      - ./cache:/app/cache
```

You can replace `#main` with any other branch or tag reference, for example `#1.5` to pin the build to tagged version
1.5.

Save the file. You will still need to create a copy of `config-example.yml` and name it `config.yml`, though with the
Docker setup nothing has actually been downloaded yet, so you will have to copy the example from the repository some
other way, e.g. [from the repo in a web browser](https://git.ianrenton.com/ian/spothole/src/branch/main/config-example.yml).

With that in place, run `docker compose up` and you should be good to go. To detach, press `d` or run the command with
the `-d` flag.

### nginx Reverse Proxy with Docker

In a containerised setup, it's typical to run an nginx reverse proxy in one container, alongside certbot for renewal
of HTTPS certificates, and then applications like Spothole in a separate container. In this case, there are a couple of
variations of the docker compose file above, and the nginx reverse proxy configuration covered [here](./nginx.md), that
you will want to make.

1. A port mapping is no longer required in the docker compose file; nginx will access into the docker container directly
   on e.g. `http://spothole:8080`
2. Spothole and nginx will need to be on the same docker network.

So your `compose.yaml` might look like this:

```yaml
services:
  spothole:
    container_name: spothole
    build:
      context: https://git.ianrenton.com/ian/spothole.git#main
    restart: unless-stopped
    networks:
      - docker-network
    volumes:
      - ./config.yml:/app/config.yml
      - ./cache:/app/cache

networks:
  docker-network:
    external: true
```

In your nginx site configuration, you'll want to refer to the Spothole container directly, and drop the block that
allows nginx to access static files directly, as these will be inaccessible in another container. So you may end up
with something like:

```nginx
server {
    server_name spothole.app;

    # Global proxy settings
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_connect_timeout 10s;
    proxy_buffering on;
    
    # Pass on IP address and host information to Spothole, in case logging this information is required
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Wellknown area for Lets Encrypt
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    
    # SSE endpoints
    location ~ ^/api/v\d*/(spots|alerts)/stream/? {
        proxy_pass http://spothole:8080;
        
        # Remove buffering, remove caching, add suitable timeouts for SSE API calls
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 24h;
        proxy_send_timeout 24h;
        proxy_set_header X-Accel-Buffering no;
        add_header Cache-Control no-store always;
        
        # Allow cross-origin requests to API
        proxy_hide_header Access-Control-Allow-Origin;
        add_header Access-Control-Allow-Origin * always; 
    }

    # Other API endpoints
    location /api/ {
        proxy_pass http://spothole:8080;
        
        # Remove buffering, remove caching, add suitable timeouts for API calls
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 30s;
        add_header Cache-Control no-store always;
        
        # Allow cross-origin requests to API
        proxy_hide_header Access-Control-Allow-Origin;
        add_header Access-Control-Allow-Origin * always;
    }

    # Templated pages and static assets
    location / {
        proxy_pass http://spothole:8080;
        proxy_read_timeout 30s;
        add_header Cache-Control "no-cache, must-revalidate" always;
    }
    
    listen 443 ssl;
    listen [::]:443 ssl;

    ssl_certificate /etc/letsencrypt/live/spothole.app/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/spothole.app/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}


server {
    if ($host = spothole.app) {
        return 301 https://$host$request_uri;
    }

    server_name spothole.app;
    listen 80;
    listen [::]:80;
    return 404;
}
```

If desired, you could even change the port on which Spothole runs from 8080 to a plain 80, in which case your
`proxy_pass` statements could drop the `:8080` suffix. Since Spothole is in a container, it can serve HTTP on port 80
if desired, because it doesn't conflict with the host system.

### Restoring the static files bypass

If you would still like to bypass Spothole's web server for the static files, and serve them with nginx, you can
do. The easiest way is to run another nginx container to serve the files, so your Spothole `compose.yaml` becomes:

```yaml
services:
  spothole:
    container_name: spothole
    build:
      context: https://git.ianrenton.com/ian/spothole.git#main
    restart: unless-stopped
    networks:
      - docker-network
    volumes:
      - ./config.yml:/app/config.yml
      - ./cache:/app/cache

  spothole-static-nginx:
    container_name: spothole-static-nginx
    build:
      context: https://git.ianrenton.com/ian/spothole.git#main
      dockerfile_inline: |
        FROM nginx:latest
        COPY static /usr/share/nginx/html
    restart: unless-stopped
    networks:
      - docker-network

networks:
  docker-network:
    external: true
```

Then you can re-add the block that handles the `/static` path in your nginx reverse proxy config, but this time
point it at the new container rather than at a filesystem path:

```nginx
    # Load static assets from the spothole-static-nginx container
    location /static/ {
        proxy_pass http://spothole-static-nginx/;
        expires 1h;
        add_header Cache-Control "public, max-age=3600, must-revalidate";
    }
```
