Can't get redirects to work via Caddyfile(more info in description)

1. Caddy version (caddy version):

devel

2. How I run Caddy:

I run caddy via caddy start in my directory containing the Caddyfile, in my case located in /etc/caddy/. I utilize Caddy for a media server, primarily for HTTPS encryption. Despite the request to provide things like domain names, they will, beyond a reasonable doubt be irrelevant here, and along with my high goals and expectations for security, they will be excluded from all logs, config files, etc. and replaced will filler text marked in italics(**)

a. System environment:

Manjaro Linux(Arch-based), utilizes systemd, installed via the AUR on the caddy2 package

b. Command:

caddy start

c. Service/unit/compose file:

# caddy.service
#
# For using Caddy with a config file.
#
# Make sure the ExecStart and ExecReload commands are correct
# for your installation.
#
# See https://caddyserver.com/docs/install for instructions.
#
# WARNING: This service does not use the --resume flag, so if you
# use the API to make changes, they will be overwritten by the
# Caddyfile next time the service is restarted. If you intend to
# use Caddy's API to configure it, add the --resume flag to the
# `caddy run` command or use the caddy-api.service file instead.

[Unit]
Description=Caddy webserver
Documentation=https://caddyserver.com/docs/
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service
StartLimitIntervalSec=14400
StartLimitBurst=10

[Service]
User=caddy
Group=caddy
Environment=XDG_DATA_HOME=/var/lib
Environment=XDG_CONFIG_HOME=/etc
ExecStart=/usr/bin/caddy run --adapter caddyfile --environ --config /etc/caddy/caddy.conf
ExecReload=/usr/bin/caddy reload --adapter caddyfile --config /etc/caddy/caddy.conf

# Do not allow the process to be restarted in a tight loop. If the
# process fails to start, something critical needs to be fixed.
Restart=on-abnormal

# Use graceful shutdown with a reasonable timeout
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5s

LimitNOFILE=1048576
LimitNPROC=512

# Hardening options
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/caddy /var/log/caddy
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
LockPersonality=true

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile(chosen to list) or JSON config:

{
email   *email@email.com*
}


# This file was moved to caddy.conf
*my.domain.com* {
	encode gzip
		log {
			output file /etc/caddy/logs/jellyfin_access.log {
				roll true				# Rotate logs, enabled by default
				roll_size_mb 5			# Set max size 5 MB
				roll_gzip true			# Whether to compress rolled files
				roll_local_time true	# Use localhost time
				roll_keep 2				# Keep at most 2 log files
				roll_keep_days 7		# Keep log files for 7 days 
			}
		}
    redir /jellfin /jellyfin/
    reverse_proxy /jellyfin/* 127.0.0.1:*myport*
}
# Edit 05/06/20 Remove Empty Brackets, Change logging format, and added Email portion. Commented out email portion for now
# Edit 05/07/20 Removed Email portion. Adding an optional part in the guide for it.
# Proof /u/NoFeedback4007 is original author. :)

3. The problem I’m having:

I can’t get redirects to work. As per the above example, trying to connect via “my.domain.com/jellyin” doesn’t redirect to “my.domain.com/jellyfin/”, and thus unless I type in the former I can’t connect.

4. Error messages and/or full log output:

N/A

5. What I already tried:

Not trying to be lazy, but not sure what else to try. Everything else, including stuff like manually typing in the former link works, just not redirects.

6. Links to relevant resources:

N/A

Simple typo! jellfinjellyfin!

You got another typo here, missing the f :stuck_out_tongue:

That said, it doesn’t look like you’re serving anything else on that domain. Why are you serving jellyfin under a subpath? I think that just complicates the setup here.

Typically the better approach is to use a subdomain per service. For example:

jellyfin.my.domain.com {
	reverse_proxy 127.0.0.1:8086
}

otherservice.my.domain.com {
	reverse_proxy 127.0.0.1:8080
}

Some reading on the topic of serving things in subpaths:

1 Like

Thanks for pointing out the spelling errors, didn’t even notice!

I use Jellyfin in combination with, Caddy, of course, and a DDNS service, which is used, of course, to redirect a URL to my IP. I would use the example you listed about, but the DDNS I use is already having the URL I use under a subdomain(myip.ddns.com), so doing the /jellyfin/ is the most convenient, if not my only option if I’m not mistaken(except for a manual port listing).

Just a tip, this is what I do for my setup…

I have a dynamic DNS domain, but I also have a regular domain. I set up CNAME entries for my regular domain to my dynamic DNS domain, i.e.:

  • example.commy.ddns.com
  • *.example.commy.ddns.com

That way, I can serve any subdomain I want with a pretty domain while still having dynamic DNS.

Also, it’s possible to go one level deeper with subdomains, i.e. *.myip.ddns.com but the thing is that Let’s Encrypt may have rules preventing this from working. I’m not sure on the status of that anymore.

The DDNS I use doesn’t seem to allow for another level in the domain itself(ip.address.ddns.com), so unless I switch to another one, that’s out of the park. Also can’t afford a domain anytime soon, otherwise I’d do that :sweat_smile:. Will definitely keep this in references for when I do though!

Also just thinking of it, a DDNS service of sorts can’t be set up with a “regular” domain? I guess this could work for pointing at different IP’s, though I don’t know if this can be done with a single domain or not. Also on the matter, when it forwards the request to the DDNS service from the “normal” domain, will that then show the DDNS URL, or will it still show the “normal” URL?

Huh, that’s surprising considering they’re only $10/year generally. That’s a bummer :frowning_face:

Yes they can, but it’s entirely dependent on the APIs that the domain registrar provides to make this possible. There’s an experimental Caddy plugin GitHub - mholt/caddy-dynamicdns: Caddy app that keeps your DNS records (A/AAAA) pointed at itself. that is meant to do just this, but it’s still a work-in-progress because it would need to individually support each domain provider for this to work well. It’s complicated. Lots of overhead to making it viable.

I think you might misunderstand how DNS works.

There’s no redirecting involved, really. Before your browser makes the request to your server, it first tries to resolve the DNS to an IP address. To do this, it contacts whatever DNS servers are configured (usually whatever handles requests to port 53 in your internal network, your router may have configured DNS servers, your own machine could have /etc/hosts configured to override some names, etc.) and asks the DNS server “hey for domain example.com, what IP do you have for me?”

The DNS server will check it’s database and reply with the IP address. There can be all kinds of rules that determine what the response will be. If there’s a CNAME record, then it needs to do another lookup against that value until it finds an A (IPv4), or possibly an AAAA (IPv6) record which defines the IP address.

Now that the browser got an answer, i.e. resolved the domain to an IP address, it’s ready to make the request. It starts making TCP packet that have the destination as that IP address.

If it’s communicating over HTTPS, then it needs to make a TLS handshake, which has some back and forth communication that needs to happen first, and part of that is SNI (Server Name Identification) where the browser tells the server “hey I want to make a secure connection to see the page for example.com please” and they agree on a secret key to encrypt the connection, then data is sent over HTTP (text protocol with a method name, path, query, headers, body).

Anyways I’m way oversimplifying, but I hope that should clear it up. All the DDNS service is doing is providing an easy to use API to dynamically update the A record for a specific subdomain they manage. When that change happens, it’s propagated throughout the DNS servers of the world to keep it up to date.

2 Likes

Great, thanks for all of that!

Nah, I’m just a teen doing techy stuff(that’s as far as I’m gonna go), I’ll be able to get a domain one day :wink:

1 Like

Have you considered a dot tk domain?

Legitimately free (short-lived, but renewable - kinda like an ACME cert…) domains. Great for those of us in a similar situation to you and looking to muck about with web technologies.

I’ve heard of those, I may look into it.

Is it safe to get the domains from dot.tk? It’s impossible to connect to the site via HTTPS, just curious if it’s safe to claim a domain and such under HTTP.

@Whitestrake I don’t know if this is the place to ask, but with Freenom for dot.tk domains, what settings do I need to tweak to forward my domain to my DDNS domain?
Also, with that, is it possible to point my domain directly at my IP(I imagine so, just don’t know how), and also use caddy with it?
Last thing, if I wanted to do something like “jellyfin.mydomain.tk”, how would I set that all up? I want that just for my media server, but still want the base domain for other things.

Sorry for all the questions, still new to all of this, and the Freenom knowledgebase isn’t helping too much…

Just an FYI for everyone, I’ve gotten pretty much everything working. Now,

Is there any way to make, for example, jellyfin.mydomain.com point to a specific port, and leave mydomain.com to point to the IP itself? I’m fine with this being done with the DDNS, I just don’t know how to set it up.

A domain name always points at an IP address - not a specific port.

It’s the program you’re using to connect to the domain name - more specifically, the protocol that program uses - that usually determines which port is used.

Port numbers are conventional. For example, if I were to point SSH at one of my domain names, it would connect to that host on port 22.

Likewise, if I type my domain name into my web browser, it will connect on port 80 (unless I type https:// first, upon which it will connect on port 443).

You could point your bare domain at one IP address and point the jellyfin subdomain at another IP address, if you wanted.

So I’d need a completely second IP to make it work with the jellyfin subdomain? Would my only other option be doing a subfolder(/jellyfin/)?

Almost definitely not required.

What is “it”, exactly? What does “working” look like?

That is an option, definitely not your only option.

It might be helpful here to define your desired behaviour.

You can configure Caddy to achieve pretty much any combination of subdomains, ports, paths, and protocols, reverse proxying to whatever upstreams you like.

Hope this helps clarify things:
I have my base URL(example.com), which is just generic and used for stuff like my Minecraft server, which requires a port entry in the game itself to connect, no problems here.
:point_down:
I have a jellyfin media server, being hosted on 8038(for illustrative purposes), which I want to be able to access at jellyfin.example.com. I would like to automatically connect to port 8038 via this URL, not needing to append a port to the end of the URL.
:point_up:

  • Note that everything is hosted on the same IP and device.

Is this setup possible? Mainly just concerned with getting the jellyfin.example.com part.

Which port you connect to is determined by your browser. Strictly speaking, there’s nothing you can do on the server side to force your browser to connect to port 8038 unless the actual port :8038 is present in the URL.

What you CAN do - what is normally done as best practice - is to disable external access to port 8038 entirely. Then, you tell Caddy to serve your site - jellyfin.example.com - on standard HTTP(S) ports (80 and 443) - and configure it to reverse proxy to port 8038 internally.

Then, you just type in the URL (no port) and it automatically connects to Caddy, which handles the rest.

Yes. Simply point both example.com and jellyfin.example.com at your DDNS (you can CNAME them to your ddns.example.com URL for convenience if you like).

That said, you seem stuck on the idea that one URL only does one port - that is not the case.

You can serve both Minecraft (default port 25565) and HTTP(S) (default ports 80 and 443) on the same URL. You could just use example.com. Set up a Caddyfile to proxy example.com to Jellyfin, then launch your Minecraft server. Minecraft users will be able to type example.com into their Minecraft client, and Jellyfin users will be able to type example.com into their browsers, and both will get what they’re looking for.

Doesn’t seem to be connecting, here’s my caddyfile for jellyfin.domain.com:

        encode gzip
                log {
                        output file /etc/caddy/logs/jellyfin_access.log {
                                roll true                               # Rotate logs, enabled by default
                                roll_size_mb 5                  # Set max size 5 MB
                                roll_gzip true                  # Whether to compress rolled files
                                roll_local_time true    # Use localhost time
                                roll_keep 2                             # Keep at most 2 log files
                                roll_keep_days 7                # Keep log files for 7 days
                        }
                }
    reverse_proxy  127.0.0.1:8038

Is this an incorrect setup for the goal mentioned eariler(direct access to jellyfin via jellyfin.domain.com)? When connecting I’m getting a timed out error, so I’m thinking it just doesn’t know where to go or something, I don’t really know.

Yep, just want a separate one for jellyfin for styling :wink:

Possibly. Try run nslookup jellyfin.example.com and confirm that it resolves to the same IP address as your own external IP. Then, double check that external HTTP(S) ports are unblocked and/or port forwarded to your Caddy server correctly.


P.S. Try to use example.com when you’re redacting domains; someone else owns domain.com. (See: https://example.com)

Dumb mistake, autofill in my browser revealed it :sweat_smile:

I had previously used a DDNS service, but now I’m not. I guess I did jellyfin.myold.ddns.com instead of my current domain, jellyfin.example.com.

I’ll make sure to look out for “rookie mistakes” in the future

1 Like