Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ Usage of ./pmoxs3backuproxy:
Debug logging
-endpoint string
S3 Endpoint without https/http , host:port
-insecure-no-tls
Disable TLS for proxy server (useful for reverse proxy setups): default: false
-key string
Server SSL key file (default "server.key")
-lookuptype string
Expand Down Expand Up @@ -107,6 +109,23 @@ Usage of ./garbagecollector:
```

# Quickstart
## Reverse Proxy / Platform Deployment Setup (fly.io, etc.)

For deployment on platforms like fly.io or behind reverse proxies where TLS termination happens at the edge, you can run the proxy in insecure mode:

```bash
pmoxs3backuproxy -endpoint your-s3-endpoint.com:443 -insecure-no-tls -bind :8007
```

This will start the proxy listening on plain HTTP, allowing the platform's load balancer or reverse proxy to handle TLS termination. This is particularly useful for:

- **fly.io deployments**: Where the platform expects backend services to run in plain HTTP
- **Kubernetes ingress**: Where TLS termination happens at the ingress controller
- **Load balancers**: Where SSL termination happens at the load balancer level
- **Docker environments**: Where a reverse proxy like nginx or traefik handles certificates

**Security Note**: Only use `-insecure-no-tls` when you have proper TLS termination upstream. Never expose the insecure proxy directly to the internet.

### Setup minio

Start minio server (either on the PVE system or on a remote system),
Expand Down Expand Up @@ -175,7 +194,9 @@ Use proxmox backup client by setting the repository and password accordingly:
# Running with Docker

Add the following to your `docker-compose.yml`, add/update your `-endpoint`, then run `docker compose up -d`. The service will be accessible at `localhost:8007`.
```

**Standard TLS Mode (default):**
```yaml
name: pmoxs3backuproxy
services:
pmoxs3backuproxy:
Expand All @@ -190,6 +211,22 @@ services:
- '8007:8007'
```

**Insecure Mode (for reverse proxy setups):**
```yaml
name: pmoxs3backuproxy
services:
pmoxs3backuproxy:
image: ghcr.io/tizbac/pmoxs3backuproxy:latest
command: -bind :8007 -endpoint your-s3-endpoint.com:443 -insecure-no-tls
container_name: pmoxs3backuproxy
hostname: pmoxs3backuproxy
restart: unless-stopped
volumes:
- /etc/localtime:/etc/localtime:ro
ports:
- '8007:8007'
```

For increased security, you can add the following security parameters without affecting container function:
```
user: '65532:65532'
Expand Down
32 changes: 22 additions & 10 deletions cmd/pmoxs3backuproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func main() {
endpointFlag := flag.String("endpoint", "", "S3 Endpoint without https/http , host:port")
bindAddress := flag.String("bind", "127.0.0.1:8007", "PBS Protocol bind address, recommended 127.0.0.1:8007, use :8007 for all")
insecureFlag := flag.Bool("usessl", false, "Use SSL for endpoint connection: default: false")
noTLSFlag := flag.Bool("insecure-no-tls", false, "Disable TLS for proxy server (useful for reverse proxy setups): default: false")
ticketExpireFlag := flag.Uint64("ticketexpire", 3600, "API Ticket expire time in seconds")
lookupTypeFlag := flag.String("lookuptype", "auto", "Bucket lookup type: auto,dns,path")
debug := flag.Bool("debug", false, "Debug logging")
Expand Down Expand Up @@ -149,24 +150,35 @@ func main() {
go S.ticketGC()
S.handleSignal()
s3backuplog.InfoPrint(
"Starting PBS api server on [%s], upstream: [%s] ssl: [%t] lookup type: [%s]",
"Starting PBS api server on [%s], upstream: [%s] ssl: [%t] lookup type: [%s] proxy-tls: [%t]",
*bindAddress,
*endpointFlag,
*insecureFlag,
*lookupTypeFlag,
!*noTLSFlag,
)

certFing := certFingeprint(*certFlag)
if certFing != nil {
s3backuplog.InfoPrint("Server certificate fingerprint is: %s", *certFing)
}
// Only check certificate fingerprint if TLS is enabled
var certFing *string
if !*noTLSFlag {
certFing = certFingeprint(*certFlag)
if certFing != nil {
s3backuplog.InfoPrint("Server certificate fingerprint is: %s", *certFing)
}

if certFing != nil && *certFing == "55:BC:29:4B:BA:B6:A1:03:42:A9:D8:51:14:9D:BD:00:D2:2A:9C:A1:B8:4A:85:E1:AF:B2:0C:48:40:D6:CC:A4" {
//Warn the user about MITM
s3backuplog.WarnPrint("You are using default supplied certificate!, do not run PVE->S3PROXY on untrusted network!!!")
if certFing != nil && *certFing == "55:BC:29:4B:BA:B6:A1:03:42:A9:D8:51:14:9D:BD:00:D2:2A:9C:A1:B8:4A:85:E1:AF:B2:0C:48:40:D6:CC:A4" {
//Warn the user about MITM
s3backuplog.WarnPrint("You are using default supplied certificate!, do not run PVE->S3PROXY on untrusted network!!!")
}
}

err := srv.ListenAndServeTLS(*certFlag, *keyFlag)
var err error
if *noTLSFlag {
s3backuplog.InfoPrint("Starting server in insecure mode (no TLS)")
err = srv.ListenAndServe()
} else {
err = srv.ListenAndServeTLS(*certFlag, *keyFlag)
}
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -679,7 +691,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.RequestURI, "/fixed_close?") && s.H2Ticket != nil && r.Method == "POST" {
wid, _ := strconv.ParseInt(r.URL.Query().Get("wid"), 10, 32)
csumindex, _ := hex.DecodeString(r.URL.Query().Get("csum"))
outFile := make([]byte, 0)
var outFile []byte
//FIDX format is documented on Proxmox Backup docs pdf
if s.Writers[int32(wid)].ReuseCSUM != "" {
//In that case we load from S3 the specified reuse index
Expand Down