mirror of
https://github.com/euzu/tuliprox.git
synced 2026-09-16 06:02:27 +02:00
- **New Features** - Added automatic `.env` loading for secrets and environment variables, with custom file paths and existing-environment precedence. - Added a `--env-file` option and a sample environment configuration template. - Increased Docker file descriptor limits for improved reliability under high connection counts. - **Bug Fixes** - Fixed title parsing for multi-byte UTF-8 characters, preventing crashes and incorrect volume extraction. - **Documentation** - Added guidance for `.env` configuration, Docker usage, restart requirements, and resolving file descriptor exhaustion.
446 lines
15 KiB
Markdown
446 lines
15 KiB
Markdown
# Docker
|
||
|
||
## Build docker image
|
||
|
||
Targets are:
|
||
|
||
- `scratch-final`
|
||
- `alpine-final`
|
||
|
||
Change into the root directory and run:
|
||
|
||
```shell
|
||
# Build for a specific architecture
|
||
docker build --rm -f docker/Dockerfile -t tuliprox --target scratch-final --build-arg RUST_TARGET=x86_64-unknown-linux-musl .
|
||
docker build --rm -f docker/Dockerfile -t tuliprox --target scratch-final --build-arg RUST_TARGET=aarch64-unknown-linux-musl .
|
||
docker build --rm -f docker/Dockerfile -t tuliprox --target scratch-final --build-arg RUST_TARGET=armv7-unknown-linux-musleabihf .
|
||
docker build --rm -f docker/Dockerfile -t tuliprox --target scratch-final --build-arg RUST_TARGET=x86_64-apple-darwin .
|
||
```
|
||
|
||
Both targets have the path prefix: `/app`
|
||
|
||
This will build the complete project and create a docker image.
|
||
|
||
To start the container, you can use the `docker-compose.yml`
|
||
But you need to change `image: ghcr.io/euzu/tuliprox:latest` to `image: tuliprox`
|
||
|
||
## Manual docker image
|
||
|
||
You want to build the binary and web folder manually and create a docker image.
|
||
|
||
To dockerize tuliprox, you need to compile a static build.
|
||
The static build can created with `bin\build_lin_static.sh`.
|
||
Description of static binary compiling is in the main `README.md`
|
||
|
||
Then you need to compile the frontend with `yarn build`
|
||
|
||
Change into the `docker` directory and copy all the needed files (look at the Dockerfile) into the current directory.
|
||
|
||
To create a docker image type:
|
||
`docker -f Dockerfile.manual build -t tuliprox .`
|
||
|
||
To start the container, you can use the `docker-compose.yml`
|
||
But you need to change `image: ghcr.io/euzu/tuliprox:latest` to `image: tuliprox`
|
||
|
||
Set timezone in docker-compose.yml like
|
||
|
||
```dockerfile
|
||
environment:
|
||
- TZ=${TZ:-Europe/Paris}
|
||
```
|
||
|
||
### Environment variables and `.env` files
|
||
|
||
Tuliprox supports loading secrets from `.env` files for `${env:VAR}` interpolation in configuration files:
|
||
|
||
- **Automatic:** Place `.env` in `./config/.env`. It is mounted into `/app/config/.env` and automatically loaded at startup.
|
||
- **Custom path via `TULIPROX_ENV_FILE`:** Mount the file into the container and set `TULIPROX_ENV_FILE=/path/to/.env`.
|
||
- **Docker Compose `env_file:`:** Add `env_file: [.env]` in `docker-compose.yml`.
|
||
|
||
> Changing a mounted `.env` file requires restarting the container (`docker compose restart`).
|
||
> When using `env_file:`, recreate the container (`docker compose up -d --force-recreate`).
|
||
|
||
## Docker Container Templates — Deployment Guide
|
||
|
||
This repository contains ready-to-use Docker Compose templates for a secure reverse proxy stack with VPN egress and CrowdSec protection. It includes
|
||
**Traefik**, **Gluetun** (WireGuard) with optional proxy sidecars, **CrowdSec** with Traefik integration, an **IPTV-org-epg** service, and an example
|
||
**Tuliprox** app wired for reverse proxying.
|
||
|
||
> **Software baseline:** Traefik v3.5, a current Rust toolchain, and a current Docker/Compose setup.
|
||
|
||
---
|
||
|
||
## Legend
|
||
|
||
| Template | Folder | Purpose | Notable Ports (internal unless published) |
|
||
| ---------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ |
|
||
| **Traefik** | `container-templates/traefik/` | Reverse proxy & TLS (ACME/DNS), dashboard, dynamic security middlewares, optional CrowdSec bouncer. | 80 `web`, 443 `websecure` |
|
||
| **Gluetun** | `container-templates/gluetun/` | VPN egress via WireGuard; sidecars provide **SOCKS5**, **HTTP**, and **Shadowsocks** proxies bound to Gluetun’s network stack. | 1080/tcp (HTTP), 1388/tcp+udp (SOCKS5), 9388/tcp+udp (Shadowsocks) |
|
||
| **CrowdSec** | `container-templates/crowdsec/` | LAPI + bouncers (Traefik & firewall) to protect services. | LAPI on `127.0.0.1:8080` (host) |
|
||
| **Tuliprox** | `container-templates/tuliprox/` | Example application container with Traefik labels and `expose: 8901` for reverse proxying. | 8901 (internal) |
|
||
| **IPTV-org-epg** | `container-templates/iptv-org/` | Generates and serves a local XMLTV guide from a manually curated channel list. | 3000 (internal) |
|
||
|
||
---
|
||
|
||
## Repository Layout (verified)
|
||
|
||
```shell
|
||
container-templates/
|
||
├─ traefik/
|
||
│ ├─ .env
|
||
│ ├─ cf-token
|
||
│ ├─ config/
|
||
│ │ ├─ traefik.yml
|
||
│ │ ├─ acme.json (create & chmod 600 if missing)
|
||
│ │ └─ dynamic/
|
||
│ │ ├─ cdn-default-router.yml
|
||
│ │ ├─ crowdsec.yml
|
||
│ │ ├─ default-security-headers.yml
|
||
│ │ ├─ gluetun-proxys.yml
|
||
│ │ ├─ https-redirect.yml
|
||
│ │ ├─ real-ip-header.yml
|
||
│ │ ├─ strip-ip-header.yml
|
||
│ │ └─ tls-security.yml
|
||
│ └─ docker-compose.yml
|
||
├─ gluetun/
|
||
│ ├─ .env.http-proxy
|
||
│ ├─ .env.socks5-proxy
|
||
│ ├─ .env.ss-proxy
|
||
│ ├─ gluetun/
|
||
│ │ ├─ .env.wg
|
||
│ │ └─ docker-compose.yml
|
||
├─ crowdsec/
|
||
│ ├─ .env.cs-bouncer-firewall
|
||
│ ├─ .env.cs-bouncer-traefik
|
||
│ ├─ crowdsec/
|
||
│ │ └─ acquis.d/
|
||
│ │ ├─ appsec.yml
|
||
│ │ ├─ docker.yml
|
||
│ │ ├─ iptables.yml
|
||
│ │ ├─ mail.yml
|
||
│ │ ├─ sshd.yml
|
||
│ │ ├─ system.yml
|
||
│ │ └─ traefik.yml
|
||
│ ├─ firewall-bouncer/
|
||
│ │ └─ config/crowdsec-firewall-bouncer.yaml
|
||
│ └─ docker-compose.yml
|
||
├─ tuliprox/
|
||
│ └─ docker-compose.yml
|
||
└─ iptv-org/
|
||
├─ data/
|
||
│ └─ channels.xml
|
||
└─ docker-compose.yml
|
||
```
|
||
|
||
---
|
||
|
||
## Prerequisites
|
||
|
||
1. **Docker & Compose**
|
||
2. **Create external networks** used across templates:
|
||
|
||
```bash
|
||
docker network create proxy-net
|
||
docker network create crowdsec-net
|
||
```
|
||
|
||
3. **DNS provider token** (e.g., Cloudflare) if you use ACME DNS-01 with Traefik.
|
||
|
||
---
|
||
|
||
## 1) Traefik (reverse proxy)
|
||
|
||
**Folder:** `container-templates/traefik/`
|
||
|
||
### Files to review
|
||
|
||
- `.env`
|
||
- Fix and fill:
|
||
- `TZ=...`
|
||
- `TRAEFIK_DASHBOARD_CREDENTIALS=<user:hashed-password>`
|
||
- `CF_API_EMAIL=<cloudflare-email>`
|
||
- `CF_DNS_API_TOKEN_FILE=/run/secrets/cloudflare`
|
||
- `cf-token`
|
||
Put **only** your DNS API token string here, then:
|
||
|
||
```bash
|
||
chmod 600 container-templates/traefik/cf-token
|
||
```
|
||
|
||
- `config/traefik.yml`
|
||
- Set your ACME email.
|
||
- Under `dnsChallenge.provider`, fix provider name if needed (**template shows `cloudclare`; use `cloudflare` or your actual provider**).
|
||
- EntryPoints `web`/`websecure` are defined; dynamic files add middlewares.
|
||
- `config/acme.json`
|
||
- Create if missing and lock down permissions:
|
||
|
||
```bash
|
||
touch container-templates/traefik/config/acme.json
|
||
chmod 600 container-templates/traefik/config/acme.json
|
||
```
|
||
|
||
### Start
|
||
|
||
```bash
|
||
docker compose -f container-templates/traefik/docker-compose.yml up -d
|
||
docker logs -f traefik
|
||
```
|
||
|
||
### Security middlewares already included
|
||
|
||
- `https-redirect.yml` (force HTTPS)
|
||
- `default-security-headers.yml` (strict defaults for CSP, HSTS, etc.)
|
||
- `tls-security.yml` (TLS options)
|
||
|
||
> Optional: `crowdsec.yml` enables the Traefik bouncer plugin if CrowdSec is running.
|
||
|
||
1. Add bouncer to your crowdsec engine
|
||
|
||
```shell
|
||
user:~$ docker exec -it crowdsec cscli bouncer add traefik-bouncer
|
||
API key for 'traefik-bouncer':
|
||
|
||
2PbAzuGn9ynn6pYsqoqd98wMJYPA/CIynySN1Lva5H8
|
||
|
||
Please keep this key since you will not be able to retrieve it!
|
||
```
|
||
|
||
2. Copy the provided key and paste it to your `crowdsec.yml` file
|
||
|
||
```yaml
|
||
crowdsecLapiKey: 2PbAzuGn9ynn6pYsqoqd98wMJYPA/CIynySN1Lva5H8
|
||
```
|
||
|
||
---
|
||
|
||
## 2) Gluetun (VPN egress + proxy sidecars)
|
||
|
||
**Folder:** `container-templates/gluetun/`
|
||
|
||
Each instance (`gluetun`) has its own `.env.wg` with WireGuard settings. Sidecars (e.g., `socks5`) use
|
||
`network_mode: service:gluetun` to share Gluetun’s network. Otherwise connect the provided proxies within your tuliprox instance through traefik.
|
||
|
||
### Configure minimum one instance (example: gluetun)
|
||
|
||
1. Edit WireGuard values:
|
||
|
||
```bash
|
||
nano container-templates/gluetun/.env.wg
|
||
# WIREGUARD_PRIVATE_KEY=...
|
||
# WIREGUARD_ADDRESSES=...
|
||
# WIREGUARD_PUBLIC_KEY=...
|
||
# WIREGUARD_ENDPOINT_IP=...
|
||
# WIREGUARD_ENDPOINT_PORT=51820
|
||
# WIREGUARD_MTU=1420
|
||
# WIREGUARD_PERSISTENT_KEEPALIVE_INTERVAL=25s
|
||
```
|
||
|
||
2. (Optional) Enable proxy sidecars by editing:
|
||
- `container-templates/gluetun/.env.socks5-proxy` (username/password & port 1388)
|
||
- `container-templates/gluetun/.env.http-proxy` (HTTP proxy on 1080)
|
||
- `container-templates/gluetun/.env.ss-proxy` (Shadowsocks on 9388)
|
||
|
||
3. Start:
|
||
|
||
```bash
|
||
docker compose -f container-templates/gluetun/docker-compose.yml up -d
|
||
docker logs -f gluetun
|
||
```
|
||
|
||
### Test from your Docker host
|
||
|
||
```bash
|
||
# Test SOCKS5(H) via traefik:
|
||
docker run --rm curlimages/curl:latest \
|
||
-sS -x "socks5h://<USER>:<PASS>@proxy.tuliprox.io:<SOCKS5_PORT>" \
|
||
https://ipinfo.io/ip
|
||
|
||
# Test HTTP(S) proxy via traefik:
|
||
docker run --rm curlimages/curl:latest \
|
||
-sS -x "https://<USER>:<PASS>@proxy.tuliprox.io:<HTTPS_PROXY_PORT>" \
|
||
https://ipinfo.io/ip
|
||
```
|
||
|
||
> Gluetun services are **exposed** to the Docker network by default, not to the host. Publish ports via Traefik or Compose if you really need external
|
||
> access (watch out for abuse/security) or want to use load balancing between your upstream proxy server. Be aware, however, that this can lead to a
|
||
> temporary block if the IP addresses change too quickly between two requests.
|
||
|
||
---
|
||
|
||
## 3) CrowdSec (LAPI + bouncers)
|
||
|
||
**Folder:** `container-templates/crowdsec/`
|
||
|
||
### Start
|
||
|
||
```bash
|
||
docker compose -f container-templates/crowdsec/docker-compose.yml up -d
|
||
docker logs -f crowdsec
|
||
```
|
||
|
||
### Configure
|
||
|
||
1. Register your crowdsec engine
|
||
|
||
```bash
|
||
docker exec -it crowdsec cscli console enroll -e context cadsgfv0hadfgoisdfhuip
|
||
```
|
||
|
||
2. Add firewall bouncer
|
||
|
||
```shell
|
||
user:~$ docker exec -it crowdsec cscli bouncer add firewall-bouncer
|
||
API key for 'firewall-bouncer':
|
||
|
||
2PbAzuGn9ynn6pYsqoqd98wMJYPA/CIynySN1Lva5H8
|
||
|
||
Please keep this key since you will not be able to retrieve it!
|
||
```
|
||
|
||
3. Edit your env file
|
||
|
||
- `.env.cs-bouncer-firewall`
|
||
- `CROWDSEC_API_KEY=2PbAzuGn9ynn6pYsqoqd98wMJYPA/CIynySN1Lva5H8`
|
||
- `CROWDSEC_LAPI_URL=http://crowdsec:8080`
|
||
|
||
> The `docker-compose.yml` maps LAPI to `127.0.0.1:8080` on the host, and mounts logs (e.g., `/var/log/traefik/`) plus acquisition files under `crowdsec/acquis.d`.
|
||
|
||
Once healthy, the Traefik (from `traefik/config/dynamic/crowdsec.yml`) and firewall bouncer can enforce decisions.
|
||
|
||
---
|
||
|
||
## 4) Tuliprox (example app)
|
||
|
||
**Folder:** `container-templates/tuliprox/`
|
||
|
||
- `docker-compose.yml`:
|
||
- Attaches to `proxy-net`.
|
||
- `expose: 8901` for reverse proxying.
|
||
- Traefik labels are included; adjust hostnames and middlewares as needed.
|
||
|
||
### Start
|
||
|
||
```bash
|
||
docker compose -f container-templates/tuliprox/docker-compose.yml up -d
|
||
docker logs -f tuliprox
|
||
```
|
||
|
||
### Example Traefik labels (adjust to your domain)
|
||
|
||
If you need to (re)apply labels, here’s a minimal pattern you can adapt:
|
||
|
||
```yaml
|
||
labels:
|
||
- "traefik.enable=true"
|
||
|
||
# HTTP
|
||
- "traefik.http.routers.tuliprox.entrypoints=web"
|
||
- "traefik.http.routers.tuliprox.rule=Host(`cdn.example.com`)"
|
||
- "traefik.http.routers.tuliprox.middlewares=redirect-to-https@file"
|
||
|
||
# HTTPS
|
||
- "traefik.http.routers.tuliprox-secure.entrypoints=websecure"
|
||
- "traefik.http.routers.tuliprox-secure.rule=Host(`cdn.example.com`)"
|
||
- "traefik.http.routers.tuliprox-secure.tls=true"
|
||
- "traefik.http.routers.tuliprox-secure.tls.certresolver=cloudflare"
|
||
- "traefik.http.routers.tuliprox-secure.middlewares=default-security-headers@file"
|
||
|
||
# Internal service port
|
||
- "traefik.http.services.tuliprox.loadbalancer.server.port=8901"
|
||
```
|
||
|
||
> The dynamic file `cdn-default-router.yml` includes placeholder hosts (e.g., `cdn.tuliprox.io`). Change these to your domain or disable that router
|
||
> by renaming the file if not used.
|
||
|
||
---
|
||
|
||
## 5) IPTV-org-epg (EPG guide)
|
||
|
||
**Folder:** `container-templates/iptv-org/`
|
||
|
||
### Configure
|
||
|
||
1. Copy the desired `<channel>` entries from the IPTV-org `sites` files to
|
||
`container-templates/iptv-org/data/channels.xml`.
|
||
2. Ensure every `xmltv_id` exactly matches the corresponding `@epg_channel_id` in Tuliprox. For example,
|
||
`xmltv_id="BBCOne.uk@LondonHD"` matches `@epg_channel_id = "BBCOne.uk@LondonHD"`. If necessary, adjust `xmltv_id` in
|
||
`channels.xml` or set the corresponding `@epg_channel_id` in `mapping.yml`.
|
||
3. Add the generated guide to the corresponding input in your `source.yml`:
|
||
|
||
```yaml
|
||
epg:
|
||
sources:
|
||
- url: http://iptv-org-epg:3000/guide.xml
|
||
```
|
||
|
||
### Start
|
||
|
||
```bash
|
||
docker compose -f container-templates/iptv-org/docker-compose.yml up -d
|
||
docker logs -f iptv-org-epg
|
||
```
|
||
|
||
The generated `guide.xml` is written to `container-templates/iptv-org/data/`.
|
||
|
||
---
|
||
|
||
## Quick Start (end-to-end)
|
||
|
||
```bash
|
||
# 0) Networks (once)
|
||
docker network create proxy-net
|
||
docker network create crowdsec-net
|
||
|
||
# 1) Traefik
|
||
cd container-templates/traefik
|
||
touch config/acme.json && chmod 600 config/acme.json
|
||
echo "<your-dns-api-token>" > cf-token && chmod 600 cf-token
|
||
# Fix .env and config/traefik.yml (ACME email, dnsChallenge provider, etc.)
|
||
docker compose up -d
|
||
|
||
# 2) Gluetun
|
||
cd ../gluetun
|
||
# Fill .env.wg and configure the main-container proxies in the local .env.* proxy files
|
||
docker compose up -d
|
||
|
||
# 3) Tuliprox
|
||
cd ../../tuliprox
|
||
docker compose up -d
|
||
|
||
# 4) CrowdSec
|
||
cd ../crowdsec
|
||
# Fill .env.cs-bouncer-*
|
||
docker compose up -d
|
||
|
||
# 5) IPTV-org-epg
|
||
cd ../iptv-org
|
||
# Fill data/channels.xml and match every xmltv_id with @epg_channel_id
|
||
docker compose up -d
|
||
```
|
||
|
||
---
|
||
|
||
## Troubleshooting & Notes
|
||
|
||
- **External networks missing:**
|
||
`network proxy-net/crowdsec-net not found` → create them first (see prerequisites).
|
||
|
||
- **ACME permissions:**
|
||
`config/acme.json` **must** exist and be `chmod 600`, or certificate storage fails.
|
||
|
||
- **DNS provider typos:**
|
||
In `config/traefik.yml`, fix `dnsChallenge.provider` (template shows `cloudclare`; use `cloudflare` or your provider).
|
||
|
||
- **Expose vs publish:**
|
||
Many services are **exposed** to Docker networks only. To reach from the host/Internet, publish ports or front them with Traefik (recommended).
|
||
|
||
- **Security:**
|
||
Be very careful exposing proxy endpoints (SOCKS5/HTTP/Shadowsocks). Require auth, rate-limit, and restrict scope as needed.
|
||
|
||
---
|
||
|
||
## Credits / Maintenance
|
||
|
||
These templates are designed to be composable and conservative by default (HTTPS redirect, strict headers, isolated networks). Review all placeholders
|
||
marked with `<...>` and domain names like `cdn.tuliprox.io` / `proxy.tuliprox.io` and adjust to your environment.
|