Reverse proxy and redirect on same directive

1. Caddy version (caddy version):

2.4.3

2. How I run Caddy:

Using docker-compose

a. System environment:

Ubuntu 20.04 with docker

b. Command:

I use this dockerfile

FROM caddy:2.4.3-builder-alpine AS builder

RUN xcaddy build \
  --with github.com/mholt/caddy-ratelimit

FROM caddy:2.4.3-alpine

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

c. Service/unit/compose file:

  slimurl_caddy_server:
    depends_on: 
      - slimurl_api
      - slimurl_portainer
    container_name: slimurl_caddy_server
    image: slimurl-caddy-server
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    environment:
        - CADDY_INGRESS_NETWORKS=caddy
    volumes:
      - slimurl_caddy_data:/data
      - slimurl_caddy_config:/config
      - $PWD/caddy-server/.Caddyfile:/etc/caddy/Caddyfile
      - $PWD/caddy-server/logs:/var/log/caddy
    networks:
      - slimurl

d. My complete Caddyfile or JSON config:

{
  order rate_limit before basicauth
  admin off
}

#To use snippet inside directive "import rate_limit_per_min {zoneName} {numRequests} {minutes}"
(rate_limit_per_min) {
  rate_limit {
      zone {args.0} {
      key    {http.request.remote.host}
      events {args.1}
      window {args.2}m
      }  
  }
}

#Import same as above snippet, first argument is file where to save logs inside the "/var/log/caddy" folder
(log_to_file) {
  log {
    format filter {
		wrap json
		fields {
			request>headers>Authorization delete
		}
  }
  output file /var/log/caddy/{args.0} {
    roll_size     500mb
    roll_keep     10
    roll_keep_for 2880h
  }
}
}


#Redirect www.api.slimurl.me/* to uri without it
www.api.slimurl.me {
  redir https://api.slimurl.me{uri}
}

#Handle the actual uri here
api.slimurl.me {
  encode zstd gzip

  reverse_proxy /*  http://slimurl_api:80

  import log_to_file apiLog.log
  
  route /user/register {
    import rate_limit_per_min register_zone 3 60
  }
  
  route /user/login {
    import rate_limit_per_min login_zone 5 20
  }
}

#Frontend
www.slimurl.me {
  redir https://slimurl.me{uri}
}

slimurl.me {
  reverse_proxy http://slimurl_frontend:80
}


3. The problem I’m having:

I want to make it so that the frontend directive, slimurl.me reverse proxies to the http://slimurl_frontend:80 only for specific routes and every other route to be forwarded to a backend route api.slimurl.me/redirect/{uri} but no matter what I try I cannot get it to work. If I try to use multiple directives my frontend either stops working or all my requests are forwarded to the backend. I would very much appreciate the help.

4. Error messages and/or full log output:

5. What I already tried:

I tried making a matcher and redirecting everything else not matched to the backend but it’s not working

slimurl.me {
  @paths {
    path /login*
    path /profile*
    path /
  }
  reverse_proxy @paths http://slimurl_frontend:80
  redir not @paths http://api.slimurl.me/redirect{uri}
}

### 6. Links to relevant resources:

The issue you’re running into is that Caddy sorts directives according to this predetermined directive order (redir gets sorted before reverse_proxy):

And also, you have the matcher syntax incorrect for your redir directive; see the matcher docs, the matcher must be a single token (no spaces) and one of three forms:

So there’s two ways to solve this. Either use a not + path matcher on redir and no matcher on reverse_proxy since redir gets sorted first OR use handle directives to implement mutual exclusivity (only the first matching handle will run):

slimurl.me {
	@notPaths not path /login* /profile* /
	redir @notPaths https://api.slimurl.me/redirect{uri}

	reverse_proxy slimurl_frontend:80
}

OR

slimuri.me {
	@paths path /login* /profile* /
	handle @paths {
		reverse_proxy slimurl_frontend:80
	}

	handle {
		redir https://api.slimurl.me/redirect{uri}
	}
}
2 Likes

Hey thank you so much for your reply.

I had to modify the directive a bit to allow .js .css and similar files but it is working great.

Thanks again :slight_smile:

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.