Asrock ipmi and caddy v2

1. Caddy version (caddy version):

v2.4.5

2. How I run Caddy:

I run Caddy v2 as a jail in truenas 12.

a. System environment:

I run Caddy as a jail in truenas.
Jail version: 12.2-release-p6

b. Command:

service caddy start

c. Service/unit/compose file:

#!/bin/sh

# PROVIDE: caddy
# REQUIRE: LOGIN DAEMON NETWORKING
# KEYWORD: shutdown

# To enable caddy, add 'caddy_enable="YES"' to /etc/rc.conf or
# /etc/rc.conf.local

# Optional settings:
# caddy_config (string):      Full path to caddy config file
#                             (/usr/local/etc/caddy/Caddyfile)
# caddy_adapter (string):     Config adapter type (caddyfile)
# caddy_directory (string):   Root for caddy storage (ACME certs, etc.)
#                             (/var/db/caddy)
# caddy_extra_flags (string): Extra flags passed to caddy start
# caddy_logdir (string):      Where caddy logs are stored
#                             (/var/log/caddy)
# caddy_logfile (string):     Location of process log (${caddy_logdir}/caddy.log)
#                             This is for startup/shutdown/error messages.
#                             To create an access log, see:
#                             caddyserver.com/docs/caddyfile/directives/log
# caddy_user (user):          User to run caddy (root)
# caddy_group (group):        Group to run caddy (wheel)
#
# This script will honor XDG_CONFIG_HOME/XDG_DATA_HOME. Caddy will create a
# .../caddy subdir in each of those. By default, they are subdirs of /var/db/caddy.
# See caddyserver.com/docs/conventions#data-directory

. /etc/rc.subr

name=caddy
rcvar=caddy_enable
desc="Powerful, enterprise-ready, open source web server with automatic HTTPS written in Go"

load_rc_config $name

# Defaults
: ${caddy_enable:=NO}
: ${caddy_adapter:=caddyfile}
: ${caddy_config:=/usr/local/etc/caddy/Caddyfile}
: ${caddy_directory:=/var/db/caddy}
: ${caddy_extra_flags:=""}
: ${caddy_logdir:="/var/log/${name}"}
: ${caddy_logfile:="${caddy_logdir}/${name}.log"}
: ${caddy_user:="root"}
: ${caddy_group:="wheel"}

# Config and base directories
: ${XDG_CONFIG_HOME:="${caddy_directory}/config"}
: ${XDG_DATA_HOME:="${caddy_directory}/data"}
export XDG_CONFIG_HOME XDG_DATA_HOME

command="/usr/local/bin/${name}"
caddy_flags="--config ${caddy_config} --adapter ${caddy_adapter}"
pidfile="/var/run/${name}/${name}.pid"

required_files="${caddy_config} ${command}"

start_precmd="caddy_precmd"
start_cmd="caddy_start"
stop_cmd="caddy_stop"

# Extra Commands
extra_commands="configtest reload"
configtest_cmd="caddy_command validate ${caddy_flags}"
reload_cmd="caddy_command reload ${caddy_flags}"

caddy_command()
{
        /usr/bin/su -m "${caddy_user}" -c "${command} $*"
}

caddy_precmd()
{
        # Create required directories and set permissions
        /usr/bin/install -d -m 755 -o "${caddy_user}" -g "${caddy_group}" ${caddy_directory}
        /usr/bin/install -d -m 700 -o "${caddy_user}" -g "${caddy_group}" ${caddy_directory}/config
        /usr/bin/install -d -m 700 -o "${caddy_user}" -g "${caddy_group}" ${caddy_directory}/data
        /usr/bin/install -d -m 755 -o "${caddy_user}" -g "${caddy_group}" ${caddy_logdir}
        /usr/bin/install -d -m 700 -o "${caddy_user}" -g "${caddy_group}" /var/run/caddy
}

caddy_start()
{
        echo -n "Starting caddy... "
        /usr/bin/su -m ${caddy_user} -c "${command} start ${caddy_flags} \
                ${caddy_extra_flags} --pidfile ${pidfile}" >> ${caddy_logfile} 2>&1
        if [ $? -eq 0 ] && ps -ax -o pid | grep -q "$(cat ${pidfile})"; then
                echo "done"
                echo "Log: ${caddy_logfile}"
        else
                echo "Error: Caddy failed to start"
                echo "Check the caddy log: ${caddy_logfile}"
        fi
}

caddy_stop()
{
        echo -n "Stopping caddy... "
        if caddy_command stop; then
                echo "done"
        else
                echo "Error: Unable to stop caddy"
                echo "Check the caddy log: ${caddy_logfile}"
        fi
}

run_rc_command "$1"

d. My complete Caddyfile or JSON config:

ipmiasrock.duckdns.org {

tls {
        dns duckdns <APIKEY>
    }

   encode gzip
   reverse_proxy /* 10.10.10.150:80
}

3. The problem I’m having:

Caddy v2 works when I reverse proxy to a normal url “ipmiasrock.duckdns.org”. But pointing to a link like domain.duckdns.org/ipmi breaks the web portal.
I was able to get it to work/load partially with this setup:
redir /ipmi /ipmi/
handle_path /ipmi/* {
reverse_proxy 10.10.10.150:80
}
I found a nginx config: (see next section)
However I was unable to confirm if this works? Since I don’t know how to translate each and ever nginx parameter…? (proxy_set_header would be the same as header_up, I guess?)

4. Error messages and/or full log output:

caddy starts without errors

5. What I already tried:

The closest config that almost works is:
redir /ipmi /ipmi/
handle_path /ipmi/* {
reverse_proxy 10.10.10.150:80
}
This is the nginx config I found…

upstream ipmi_backend {
# the ipmi server
server 192.168.5.20:443;
keepalive 64;
}

server {
# nginx listens to this
listen 80;
# the virtual host name of this
server_name $YOUR_SUBDOMAIN_HERE;
location / {
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options “”;
proxy_set_header X-Content-Type-Options “”;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://ipmi_backend;
proxy_http_version 1.1;
proxy_pass_request_headers on;
proxy_set_header Connection “keep-alive”;
proxy_store off;
}
}

6. Links to relevant resources:

Please use backticks for code fences when posting, i.e. ``` on their own lines before and after configs and logs, so that whitespace and formatting is preserved. It’s quite difficult to read your post without it.

You’ll need to be more specific by what you mean when you say “not working” or “partially working”. We don’t know what that means. It could be any number of things.

As for what you’ve tried, handle_path strips the path prefix before handling anything within it, which means if the request had /impi/foo then it would proxy to the upstream with just /foo instead. Are you sure that’s what you need? The nginx config example you gave doesn’t strip the path prefix.

None of the header operations in that nginx config are things you need in Caddy – the ones that are already done automatically by Caddy (i.e. X-Forwarded-For).

What do you see when you make requests with curl -v?

Turn on debug mode in Caddy to see more details in your logs. Add this at the top of your Caddyfile:

{
	debug
}
1 Like

Dear Francis,

Thank you for the reply. When I surf to …/ipmi it automatically redirects to …/index.html instead of …/ipmi/index.html
But this is what I get (look at the upper right and left corner) vs what I would normally see:

This is what I get with curl:

root@CurlJail:~ # curl -I 10.10.10.150
HTTP/1.0 302 Redirect
Server: GoAhead-Webs
Date: Thu Nov  5 13:13:40 2009
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/html
Location: http://10.10.10.150/index.html

I’ve enabled debug mode, and this is what I get when I surf to the …/ipmi page:

root@CaddyJail:/usr/local/etc/caddy # caddy run
2021/10/09 12:38:30.017 INFO    using adjacent Caddyfile
2021/10/09 12:38:30.021 WARN    input is not formatted with 'caddy fmt' {"adapter": "caddyfile", "file": "Caddyfile", "line": 5}
2021/10/09 12:38:30.022 INFO    admin   admin endpoint started  {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["localhost:2019", "[::1]:2019", "127.0.0.1:2019"]}
2021/10/09 12:38:30.022 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0xc000158770"}
2021/10/09 12:38:30.023 INFO    http    server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2021/10/09 12:38:30.023 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "srv0"}
2021/10/09 12:38:30.024 INFO    tls     cleaning storage unit   {"description": "FileStorage:/root/.local/share/caddy"}
2021/10/09 12:38:30.024 DEBUG   http    starting server loop    {"address": "[::]:443", "http3": false, "tls": true}
2021/10/09 12:38:30.024 DEBUG   http    starting server loop    {"address": "[::]:80", "http3": false, "tls": false}
2021/10/09 12:38:30.024 INFO    http    enabling automatic TLS certificate management   {"domains": ["mydomain.duckdns.org"]}
2021/10/09 12:38:30.043 INFO    tls     finished cleaning storage units
2021/10/09 12:38:30.092 DEBUG   tls     loading managed certificate     {"domain": "mydomain.duckdns.org", "expiration": "2022/01/02 16:10:34.000", "issuer_key": "acme-v02.api.letsencrypt.org-directory", "storage": "FileStorage:/root/.local/share/caddy"}
2021/10/09 12:38:35.323 DEBUG   tls.cache       added certificate to cache      {"subjects": ["mydomain.duckdns.org"], "expiration": "2022/01/02 16:10:34.000", "managed": true, "issuer_key": "acme-v02.api.letsencrypt.org-directory", "hash": "ae894f8eg41e8g4e88eg4th4dg8h4th9f4g5s6g4r5g1g89s48qezqzhththvb89"}
2021/10/09 12:38:35.324 INFO    autosaved config (load with --resume flag)      {"file": "/root/.config/caddy/autosave.json"}
2021/10/09 12:38:35.324 INFO    serving initial configuration
2021/10/09 12:38:42.695 DEBUG   tls.handshake   choosing certificate    {"identifier": "mydomain.duckdns.org", "num_choices": 1}
2021/10/09 12:38:42.695 DEBUG   tls.handshake   default certificate selection results   {"identifier": "mydomain.duckdns.org", "subjects": ["mydomain.duckdns.org"], "managed": true, "issuer_key": "acme-v02.api.letsencrypt.org-directory", "hash": "ae894f8eg41e8g4e88eg4th4dg8h4th9f4g5s6g4r5g1g89s48qezqzhththvb89"}
2021/10/09 12:38:42.695 DEBUG   tls.handshake   matched certificate in cache    {"subjects": ["mydomain.duckdns.org"], "managed": true, "expiration": "2022/01/02 16:10:34.000", "hash": "ae894f8eg41e8g4e88eg4th4dg8h4th9f4g5s6g4r5g1g89s48qezqzhththvb89"}
2021/10/09 12:38:42.769 DEBUG   http.handlers.rewrite   rewrote request {"request": {"remote_addr": "10.10.10.15:14928", "proto": "HTTP/2.0", "method": "GET", "host": "mydomain.duckdns.org", "uri": "/ipmi/", "headers": {"Sec-Fetch-Dest": ["document"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-User": ["?1"], "Te": ["trailers"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Site": ["none"], "Accept-Language": ["nl,en-US;q=0.7,en;q=0.3"], "Accept-Encoding": ["gzip, deflate, br"], "Cookie": ["SessionLang=EN; test=1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "mydomain.duckdns.org"}}, "method": "GET", "uri": "/"}
2021/10/09 12:38:42.780 DEBUG   http.handlers.reverse_proxy     upstream roundtrip      {"upstream": "10.10.10.150:80", "request": {"remote_addr": "10.10.10.15:14928", "proto": "HTTP/2.0", "method": "GET", "host": "mydomain.duckdns.org", "uri": "/", "headers": {"Accept-Language": ["nl,en-US;q=0.7,en;q=0.3"], "Accept-Encoding": ["gzip, deflate, br"], "Cookie": ["SessionLang=EN; test=1"], "Sec-Fetch-Site": ["none"], "X-Forwarded-Proto": ["https"], "X-Forwarded-For": ["10.10.10.15"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Dest": ["document"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-User": ["?1"], "Te": ["trailers"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "mydomain.duckdns.org"}}, "headers": {"Content-Type": ["text/html"], "Location": ["http://mydomain.duckdns.org/index.html"], "Server": ["GoAhead-Webs"], "Date": ["Thu Nov  5 13:13:40 2009"], "Pragma": ["no-cache"], "Cache-Control": ["no-cache"]}, "status": 302}

Thanks again for your time and effort.

Okay, then you’re running into this:

If the upstream app isn’t set up to be proxied in a subpath, then there’s nothing you can do to fix that. You’ll need to use different ports or different subdomains for each service you want to proxy instead of a subpath.

1 Like

Dear Francis,

Okay, thank you for your time. I’ve assigned another subdomain to it now, instead of a subpath. Which works fine as expected.

Kind regards,
Michiel

1 Like