CFTS Internal

rproxy Caddy Overview for New Admins

Last updated: 2026-05-27

This document is the plain-English overview of the CFTS reverse proxy. Start here if you are new to the setup, especially if you need to understand what Caddy is doing or read the logs without being deep into Linux.

What This Server Does

rproxy.cfts.co is the front door for many CFTS web services.

People on the internet or LAN visit names such as:

docs.cfts.co
tickets.cfts.co
inventory.cfts.co
rp-logs.cfts.co

Those requests arrive at Caddy on rproxy.cfts.co. Caddy then decides what to do:

  • serve HTTPS certificates
  • redirect HTTP to HTTPS for known hostnames
  • block unknown HTTP hostnames
  • allow or deny access based on source IP
  • add security headers where safe
  • show shared Caddy error pages for Caddy-owned 403, 404, and 5xx errors
  • proxy allowed traffic to the correct internal server
  • write access logs

In simple terms: Caddy is the gatekeeper and traffic router. Most applications still do their own login and app logic behind it.

Traffic Flow

flowchart LR
    User["User browser"] --> DNS["DNS name, for example docs.cfts.co"]
    DNS --> Caddy["Caddy on rproxy.cfts.co"]
    Caddy --> Decision["Caddy checks hostname, HTTPS, LAN rules, headers"]
    Decision --> App["Internal app server"]
    Decision --> Deny["Caddy 403 page"]
    Caddy --> Logs["Caddy JSON logs"]
    Logs --> Report["GoAccess report at rp-logs.cfts.co"]

If the request is allowed, Caddy passes it to an internal app such as 172.16.198.22:8090.

If the request is not allowed, Caddy can stop it before it reaches the app.

Important Docs

Use these in this order:

Document Use it for
Project-Documentation/00. rproxy Caddy Overview For New Admins.md Plain-English orientation.
Project-Documentation/03. rproxy Function and Feature Synopsis.md Shared baseline for future user and technical documentation.
Project-Documentation/02. rproxy Exposure Matrix.md Which hostname points where, whether it is public or LAN-only, and what log file it uses.
Project-Documentation/01. Caddy Reverse Proxy Operations.md Operational commands, deployment steps, and deeper maintenance notes.
observability/README.md Paste-safe log dashboard install/update runbook.

Access Patterns

There are three common access patterns.

Pattern What it means Examples
Public Anyone can reach the Caddy route. The upstream app may still require login. docs.cfts.co, tickets.cfts.co, redmine.cfts.co, tracks.cfts.co
LAN-only The DNS name exists publicly, but Caddy only allows clients from 172.16.198.0/24. Other clients get 403. download.cfts.co, inventory.cfts.co, rp-logs.cfts.co, ai.cfts.co
Mixed Some paths are public, some are LAN-only or protected by Caddy Basic Auth. isp-status.cfts.co

Do not assume a public DNS name means the service is open to the public. Several names are intentionally LAN-only.

What The Error Pages Mean

Caddy has shared custom pages for Caddy-owned errors:

Status Plain meaning Common cause
403 Caddy understood the request but blocked access. Client is outside the LAN for a LAN-only site.
404 Caddy did not find a matching Caddy-owned route or static file. Wrong URL on a Caddy-served static site.
500 Caddy hit a server-side problem. Caddy-side error or upstream connection problem, depending on the route.

Important: if an upstream app returns its own 404 or 500, Caddy usually passes that through unchanged. For example, a docs app 404 is normally the docs app talking, not the shared Caddy 404 page.

Reading Logs Without Linux

Use the dashboard first:

https://rp-logs.cfts.co/

This is LAN-only. If you open it from outside the LAN, Caddy should show 403.

The dashboard is generated by GoAccess every five minutes from Caddy JSON logs. It is a static HTML report, not a separate always-running web app.

Good first things to look at:

Dashboard area What it tells you
Total Requests Overall traffic volume in the selected date range.
Failed Requests Non-success responses. Useful as a quick health smell test.
Not Found Number of 404 responses. A sudden jump can mean broken links or scanners.
Requested Files / URLs Most-requested paths. Useful for seeing what people and bots are hitting.
Static Requests CSS, JS, images, icons, and other static files.
Not Found URLs Which missing paths are being requested. Great for spotting /wp-login.php, /.env, and other scanner noise.
Hosts / Visitors Which clients are making requests. Use carefully; NAT and proxies can group many users behind one IP.
Status Codes The mix of 200, 301/308, 401, 403, 404, and 5xx.

Status Code Cheat Sheet

Code Meaning Usually OK?
200 Request succeeded. Yes.
301 / 308 Redirect, usually HTTP to HTTPS. Yes, if expected.
401 Authentication required. Yes for protected areas.
403 Forbidden by Caddy or the app. Yes for LAN-only sites hit from outside; investigate if a LAN user is blocked.
404 Not found. A few are normal; a spike may mean broken links or scanners.
500 Server error. Investigate.
502 / 503 / 504 Caddy could not successfully reach or use the upstream app. Investigate the upstream app or network path.

Normal Things You May See

These can be normal:

  • 403 on LAN-only services when tested from outside the LAN.
  • 401 on protected status/admin paths.
  • random requests for /.env, /wp-login.php, /phpmyadmin, and other scanner paths.
  • some 404 entries from bots or old links.
  • HTTP-to-HTTPS redirects on known hostnames.

Things Worth Investigating

Look closer when you see:

  • a public app returning lots of 500, 502, 503, or 504
  • a sudden jump in Failed Requests
  • a normally quiet service getting lots of traffic
  • many 404s for real app paths, not scanner paths
  • a LAN user getting 403 on a LAN-only service
  • Caddy reload failure mentioning permission denied
  • rp-logs.cfts.co not updating for more than five minutes

Minimal Linux Checks

Run commands one line at a time.

Check Caddy:

systemctl status caddy --no-pager -l

Validate Caddy config:

sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile

Reload Caddy after a valid config change:

sudo systemctl reload caddy

Read recent Caddy service errors:

journalctl -u caddy -n 80 --no-pager -l

Check the log dashboard generator:

systemctl status caddy-goaccess-report.service --no-pager -l

Check the dashboard refresh timer:

systemctl list-timers caddy-goaccess-report.timer --no-pager

Check the generated dashboard file:

ls -lh /var/www/caddy-log-report/index.html

Common Problems And First Fixes

Symptom Likely cause First place to look
Caddy reload fails with opening log writer and permission denied A configured log file does not exist or is not owned by caddy. Project-Documentation/01. Caddy Reverse Proxy Operations.md, Access Log Permissions section.
rp-logs.cfts.co shows 403 You are outside the LAN or not coming from 172.16.198.0/24. Test from LAN or VPN path that lands inside the allowed range.
Log dashboard stopped updating Timer/service failed or GoAccess render failed. systemctl status caddy-goaccess-report.service --no-pager -l
Dashboard installer says Renderer source is stale The uploaded observability/goaccess/render-caddy-goaccess-report.sh is old. Re-upload the full current observability folder.
Browser gets app error but Caddy looks healthy Upstream app may be unhealthy. Check the specific app VM/service named in the exposure matrix.
External user gets 403 for a LAN-only hostname Expected behavior. Confirm whether the hostname is listed as LAN-only in the exposure matrix.

How To Think About Changes

Before changing a hostname, access rule, upstream, or log file:

  1. Check Project-Documentation/02. rproxy Exposure Matrix.md.
  2. Make the smallest Caddy change possible.
  3. Make sure any new log file exists and is owned by caddy.
  4. Run sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile.
  5. Reload Caddy.
  6. Test the affected hostname in a browser or with curl -I.
  7. Update the matrix and operations docs.

The safest mindset: Caddy is shared front-door infrastructure. Small changes, one at a time, with validation before reload.