Caddyfile with Docker SSL issue

1. Output of caddy version:

latest

2. How I run Caddy:

sudo docker run -d -p 80:80 -p 443:443 --name caddy -v /etc/Caddyfile:/etc/caddy/Caddyfile -v /etc/caddy:/root/.local/share/caddy -v caddy_data:/data --restart on-failure caddy:2

a. System environment:

Google Cloud VM

b. Command:

sudo docker run -d -p 80:80 -p 443:443 --name caddy -v /etc/Caddyfile:/etc/caddy/Caddyfile -v /etc/caddy:/root/.local/share/caddy -v caddy_data:/data --restart on-failure caddy:2

c. Service/unit/compose file:

sudo docker run -d --name vaultwarden -v /srv/vaultwarden:/data -e WEBSOCKET_ENABLED=true -p 127.0.0.1:8080:80 -p 127.0.0.1:3012:3012 --restart on-failure vaultwarden/server:latest

d. My complete Caddy config:

cybertrusty.com:443 {
  log {
    level INFO
    output file {$LOG_FILE} {
      roll_size 10MB
      roll_keep 10
    }
  }
'
  # Use the ACME HTTP-01 challenge to get a cert for the configured domain.
 '
 tls myemail@cybertrusty.com

  # This setting may have compatibility issues with some browsers
  # (e.g., attachment downloading on Firefox). Try disabling this
  # if you encounter issues.
  encode gzip

  # Notifications redirected to the WebSocket server
  reverse_proxy /notifications/hub vaultwarden:3012

  # Proxy everything else to Rocket
  reverse_proxy bitwarden:80 {
       # Send the true remote IP to Rocket, so that bitwarden_rs can put this in the
       # log, so that fail2ban can ban the correct IP.
       header_up X-Real-IP {remote_host}
  }
}

3. The problem I’m having:

I am trying to run vaultwarden following these instructions.

I am using a custom domain name with a google public cloud server. It appears that the SSL certificate is obtained properly using letsencrypt and I have ports 443 and 80 open and port scanning the public IP confirms the same.

4. Error messages and/or full log output:

Open ssl test below


openssl s_client -connect localhost:443 -servername cybertrusty.com

I am getting a 400 bad request. 

Caddyfile log

"level":"info","ts":1659914806.2908592,"logger":"admin","msg":"stopped previous server","address":"tcp/localhost:2019"}
{"level":"info","ts":1659914806.290912,"msg":"shutdown complete","signal":"SIGTERM","exit_code":0}
{"level":"info","ts":1659914813.8599963,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1659914813.8613603,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1659914813.8621848,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1659914813.862415,"logger":"http","msg":"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}
{"level":"info","ts":1659914813.8626602,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1659914813.8626099,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0000fe850"}
{"level":"info","ts":1659914813.863309,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["cybertrusty.com"]}
{"level":"info","ts":1659914813.8633773,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1659914813.8641992,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1659914813.864218,"msg":"serving initial configuration"}
{"level":"info","ts":1659914813.878931,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1659915021.3273964,"msg":"shutting down apps, then terminating","signal":"SIGTERM"}
{"level":"warn","ts":1659915021.400887,"msg":"exiting; byeee!! đź‘‹","signal":"SIGTERM"}
{"level":"info","ts":1659915021.5516841,"logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0xc0000fe850"}
{"level":"info","ts":1659915021.5552142,"logger":"admin","msg":"stopped previous server","address":"tcp/localhost:2019"}
{"level":"info","ts":1659915021.555237,"msg":"shutdown complete","signal":"SIGTERM","exit_code":0}
{"level":"info","ts":1659915027.2087235,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1659915027.2097552,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1659915027.211228,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1659915027.2115738,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000628b60"}
{"level":"info","ts":1659915027.212287,"logger":"http","msg":"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}
{"level":"info","ts":1659915027.2123206,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1659915027.2134144,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1659915027.2135906,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["cybertrusty.com"]}
{"level":"info","ts":1659915027.2206006,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1659915027.2296882,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1659915027.2297075,"msg":"serving initial configuration"}

5. What I already tried:

I tried to follow a few different guides to install Vaultwarden but they all seem to fail the HTTPS portion. I don’t see any errors in the caddy log file so I’m not sure where to go starting with the open SSL 400 bad request error.

6. Links to relevant resources:

It won’t let me post the URL that I followed for setup.

I think this needs to be vaultwarden, not bitwarden.

I think what’s happening, from making a request to your domain, is that Caddy proxies to bitwarden:80 which for some reason resolves to 127.0.0.1:80 which ends up hitting Caddy, so it ends up in an infinite loop of HTTP->HTTPS redirects, since Caddy will redirect incoming requests on port 80 (HTTP) to HTTPS.

Thanks for the quick reply, I’ve spent too much time on trying to get this to work the last week. I made the changed and restarted caddy and same ssl error. Here is the new log.


"level":"info","ts":1659915021.5552142,"logger":"admin","msg":"stopped previous server","address":"tcp/localhost:2019"}
{"level":"info","ts":1659915021.555237,"msg":"shutdown complete","signal":"SIGTERM","exit_code":0}
{"level":"info","ts":1659915027.2087235,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1659915027.2097552,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1659915027.211228,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1659915027.2115738,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000628b60"}
{"level":"info","ts":1659915027.212287,"logger":"http","msg":"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}
{"level":"info","ts":1659915027.2123206,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1659915027.2134144,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1659915027.2135906,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["cybertrusty.com"]}
{"level":"info","ts":1659915027.2206006,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1659915027.2296882,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1659915027.2297075,"msg":"serving initial configuration"}
{"level":"info","ts":1659922273.8368351,"msg":"shutting down apps, then terminating","signal":"SIGTERM"}
{"level":"warn","ts":1659922273.837098,"msg":"exiting; byeee!! đź‘‹","signal":"SIGTERM"}
{"level":"info","ts":1659922273.8633668,"logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0xc000628b60"}
{"level":"info","ts":1659922273.8728704,"logger":"admin","msg":"stopped previous server","address":"tcp/localhost:2019"}
{"level":"info","ts":1659922273.8729255,"msg":"shutdown complete","signal":"SIGTERM","exit_code":0}
{"level":"info","ts":1659922275.7024856,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1659922275.7061553,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1659922275.7078538,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1659922275.7082627,"logger":"http","msg":"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}
{"level":"info","ts":1659922275.708264,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0002f5030"}
{"level":"info","ts":1659922275.708364,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1659922275.7089703,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1659922275.709076,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["cybertrusty.com"]}
{"level":"info","ts":1659922275.7103777,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1659922275.7109945,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1659922275.711013,"msg":"serving initial configuration"}

What does it mean, caddyfile input is not formatted? Should I ignore it?

BTW, from network engineering side, usually we use reverse proxy when we have a web facing service and an appliance on the DMZ and we reverse proxy traffic (ssl) to another host IP behind the firewall in the TRUST/LAN zone. So in this case, since I’m using Google cloud, and a public IP, I don’t understand what the reverse proxy statement is for. I am using this strictly on a public IP on the Google cloud VM.

What “SSL error”? There’s no errors in your config.

If I load cybertrusty.com in my browser, I still get the infinite redirects.

Do you have something else in front of Caddy?

That’s just a suggestion that you should run caddy fmt --overwrite on your Caddyfile to clean up the syntax and indentation. Since you’re running in Docker, it’s a bit trickier to run the formatter, but you can do it with docker exec. You can ignore that safely, it’s just a warning.

Caddy is your web server that terminates TLS, and it uses reverse_proxy to send the requests to vaultwarden which has its own HTTP server, but isn’t set up for automating HTTPS provisioning.

does this mean anything?

$ curl --head https://cybertrusty.com
HTTP/2 308
date: Mon, 08 Aug 2022 06:28:56 GMT
location: https://cybertrusty.com/
server: Caddy
server: Caddy

$ curl --head http://cybertrusty.com
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://cybertrusty.com/
Server: Caddy
Date: Mon, 08 Aug 2022 06:31:55 GMT

Browser developer tools:

outerHTML: "<body id=\"t\" style=\"font-family: system-ui, sans-serif; font-size: 75%\" jstcache=\"0\" class=\"neterror\">\n  <div id=\"main-frame-error\" class=\"interstitial-wrapper\" jstcache=\"0\">\n    <div id=\"main-content\" jstcache=\"0\">\n      <div class=\"icon icon-page-error\" jseval=\"updateIconClass(this.classList, iconClass)\" alt=\"\" jstcache=\"2\"></div>\n      <div id=\"main-message\" jstcache=\"0\">\n        <h1 jstcache=\"0\">\n          <span jsselect=\"heading\" jsvalues=\".innerHTML:msg\" jstcache=\"14\">This page isn’t working right now</span>\n          <a id=\"error-information-button\" class=\"hidden\" onclick=\"toggleErrorInformationPopup();\" jstcache=\"0\"></a>\n        </h1>\n        <p jsselect=\"summary\" jsvalues=\".innerHTML:msg\" jstcache=\"3\"><strong jscontent=\"hostName\" jstcache=\"27\">cybertrusty.com</strong> redirected you too many times.</p>\n        <div id=\"https-upgrades-message\" class=\"hidden\" jstcache=\"0\">\n          <p id=\"https-upgrades-message-details\" jsselect=\"httpsUpgradesMessage\" jsvalues=\".innerHTML:msg\" class=\"hidden\" jstcache=\"15\" style=\"display: none;\"></p>\n        </div>\n        <!--The suggestion list and error code are normally presented inline,\n          in which case error-information-popup-* divs have no effect. When\n          error-information-popup-container has the use-popup-container class, this\n          information is provided in a popup instead.-->\n        <div id=\"error-information-popup-container\" jstcache=\"0\">\n          <div id=\"error-information-popup\" jstcache=\"0\">\n            <div id=\"error-information-popup-box\" jstcache=\"0\">\n              <div id=\"error-information-popup-content\" jstcache=\"0\">\n                <div id=\"suggestions-list\" style=\"\" jsdisplay=\"(suggestionsSummaryList &amp;&amp; suggestionsSummaryList.length)\" jstcache=\"21\">\n                  <p jsvalues=\".innerHTML:suggestionsSummaryListHeader\" jstcache=\"23\"></p>\n                  <ul jsvalues=\".className:suggestionsSummaryList.length == 1 ? 'single-suggestion' : ''\" jstcache=\"24\" class=\"single-suggestion\">\n                    <li jsselect=\"suggestionsSummaryList\" jsvalues=\".innerHTML:summary\" jstcache=\"26\" jsinstance=\"*0\">To fix this issue, try <a jsvalues=\"href:learnMoreUrl\" id=\"clear-cookies-link\" jstcache=\"28\" href=\"https://go.microsoft.com/fwlink/?linkid=2112473\">clearing your cookies</a>.</li>\n                  </ul>\n                </div>\n                <div class=\"error-code\" jscontent=\"errorCode\" jstcache=\"22\">ERR_TOO_MANY_REDIRECTS</div>\n                <p id=\"error-information-popup-close\" jstcache=\"0\">\n                  <a class=\"link-button\" jscontent=\"closeDescriptionPopup\" onclick=\"toggleErrorInformationPopup();\" jstcache=\"25\">null</a>\n                </p>\n              </div>\n            </div>\n          </div>\n        </div>\n        <div id=\"diagnose-frame\" class=\"hidden\" jstcache=\"0\"></div>\n        <div id=\"download-links-wrapper\" class=\"hidden\" jstcache=\"0\">\n          <div id=\"download-link-wrapper\" jstcache=\"0\">\n            <a id=\"download-link\" class=\"link-button\" onclick=\"downloadButtonClick()\" jsselect=\"downloadButton\" jscontent=\"msg\" jsvalues=\".disabledText:disabledMsg\" jstcache=\"10\" style=\"display: none;\">\n            </a>\n          </div>\n          <div id=\"download-link-clicked-wrapper\" class=\"hidden\" jstcache=\"0\">\n            <div id=\"download-link-clicked\" class=\"link-button\" jsselect=\"downloadButton\" jscontent=\"disabledMsg\" jstcache=\"19\" style=\"display: none;\">\n            </div>\n          </div>\n        </div>\n        <div id=\"offline-content-list\" hidden=\"\" jstcache=\"0\">\n          <div class=\"offline-content-list-title\" jsselect=\"offlineContentList\" jscontent=\"title\" jstcache=\"16\" style=\"display: none;\"></div>\n          <div id=\"offline-content-suggestions\" jstcache=\"0\"></div>\n          <div class=\"offline-content-list-action\" jstcache=\"0\">\n            <a class=\"link-button\" onclick=\"launchDownloadsPage()\" jsselect=\"offlineContentList\" jscontent=\"actionText\" jstcache=\"20\" style=\"display: none;\">\n            </a>\n          </div>\n        </div>\n        <div id=\"offline-content-summary\" onclick=\"launchDownloadsPage()\" hidden=\"\" jstcache=\"0\">\n          <div class=\"offline-content-summary-images\" jstcache=\"0\">\n            <div class=\"offline-content-summary-image-truncate\" jstcache=\"0\">\n              <img id=\"earth\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIgMmM1LjUyIDAgMTAgNC40OCAxMCAxMHMtNC40OCAxMC0xMCAxMFMyIDE3LjUyIDIgMTIgNi40OCAyIDEyIDJ6TTQgMTJoNC40YzMuNDA3LjAyMiA0LjkyMiAxLjczIDQuNTQzIDUuMTI3SDkuNDg4djIuNDdhOC4wMDQgOC4wMDQgMCAwIDAgMTAuNDk4LTguMDgzQzE5LjMyNyAxMi41MDQgMTguMzMyIDEzIDE3IDEzYy0yLjEzNyAwLTMuMjA2LS45MTYtMy4yMDYtMi43NWgtMy43NDhjLS4yNzQtMi43MjguNjgzLTQuMDkyIDIuODctNC4wOTIgMC0uOTc1LjMyNy0xLjU5Ny44MTEtMS45N0E4LjAwNCA4LjAwNCAwIDAgMCA0IDEyeiIgZmlsbD0iIzNDNDA0MyIvPjwvc3ZnPg==\" jstcache=\"0\">\n            </div>\n            <div class=\"offline-content-summary-image-truncate\" jstcache=\"0\">\n              <img id=\"music-note\" src=\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgM3Y5LjI2Yy0uNS0uMTctMS0uMjYtMS41LS4yNkM4IDEyIDYgMTQgNiAxNi41UzggMjEgMTAuNSAyMXM0LjUtMiA0LjUtNC41VjZoNFYzaC03eiIgZmlsbD0iIzNDNDA0MyIvPjwvc3ZnPg==\" jstcache=\"0\">\n            </div>\n            <div class=\"offline-content-summary-image-truncate\" jstcache=\"0\">\n              <img id=\"video\" src=\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTcgMTAuNVY3YTEgMSAwIDAgMC0xLTFINGExIDEgMCAwIDAtMSAxdjEwYTEgMSAwIDAgMCAxIDFoMTJhMSAxIDAgMCAwIDEtMXYtMy41bDQgNHYtMTFsLTQgNHoiIGZpbGw9IiMzQzQwNDMiLz48L3N2Zz4=\" jstcache=\"0\">\n            </div>\n            <div jstcache=\"0\">\n              <!-- Pump Follow Up Bug #20954431 -->\n            </div>\n          </div>\n          <div class=\"offline-content-summary-description\" jsselect=\"offlineContentSummary\" jscontent=\"description\" jstcache=\"17\" style=\"display: none;\">\n          </div>\n          <a class=\"offline-content-summary-action link-button\" jsselect=\"offlineContentSummary\" jscontent=\"actionText\" jstcache=\"18\" style=\"display: none;\">\n          </a>\n        </div>\n      </div>\n    </div>\n    <div id=\"buttons\" class=\"nav-wrapper suggested-left\" jstcache=\"0\">\n      <div id=\"control-buttons\" hidden=\"\" jstcache=\"0\">\n        <button id=\"show-saved-copy-button\" class=\"blue-button text-button\" onclick=\"showSavedCopyButtonClick()\" jsselect=\"showSavedCopyButton\" jscontent=\"msg\" jsvalues=\"title:title; .primary:primary\" jstcache=\"9\" style=\"display: none;\">\n        </button><button id=\"reload-button\" class=\"blue-button text-button\" onclick=\"reloadButtonClick(this.url);\" jsselect=\"reloadButton\" jsvalues=\".url:reloadUrl\" jscontent=\"msg\" jstcache=\"8\" style=\"display: none;\"></button>\n        \n        <button id=\"download-button\" class=\"blue-button text-button\" onclick=\"downloadButtonClick()\" jsselect=\"downloadButton\" jscontent=\"msg\" jsvalues=\".disabledText:disabledMsg\" jstcache=\"10\" style=\"display: none;\">\n        </button>\n      </div>\n      <div id=\"details-buttons\" jstcache=\"0\">\n        <button id=\"details-button\" onclick=\"detailsButtonClick(); toggleHelpBox()\" jscontent=\"details\" jsdisplay=\"(suggestionsDetails &amp;&amp; suggestionsDetails.length > 0) || diagnose\" jsvalues=\".detailsText:details; .hideDetailsText:hideDetails;\" jstcache=\"11\" class=\"singular\" style=\"display: none;\"></button>\n      </div>\n    </div>\n    <div id=\"details\" class=\"hidden\" jstcache=\"0\">\n      <div class=\"suggestions\" jsselect=\"suggestionsDetails\" jstcache=\"4\" jsinstance=\"*0\" style=\"display: none;\">\n        <div class=\"suggestion-header\" jsvalues=\".innerHTML:header\" jstcache=\"12\"></div>\n        <div class=\"suggestion-body\" jsvalues=\".innerHTML:body\" jstcache=\"13\"></div>\n      </div>\n    </div>\n    <div id=\"game-buttons\" jsdisplay=\"!!showGameButtons\" jstcache=\"1\" style=\"display: none;\">\n      <span id=\"game-message\" jscontent=\"playGameMsg\" jstcache=\"5\"></span>\n      <div class=\"managed-icon\" jsdisplay=\"!!disabledGame\" jstcache=\"6\"></div>\n      <button id=\"game-button\" onclick=\"launchGame()\" jsselect=\"gameButton\" jscontent=\"msg\" jstcache=\"7\"></button>\n    </div>\n  </div>\n  <div id=\"sub-frame-error\" jstcache=\"0\">\n    <!-- Show details when hovering over the icon, in case the details are\n         hidden because they're too large. -->\n    <div class=\"icon icon-page-error\" jseval=\"updateIconClass(this.classList, iconClass)\" jstcache=\"2\"></div>\n    <div id=\"sub-frame-error-details\" jsselect=\"summary\" jsvalues=\".innerHTML:msg\" jstcache=\"3\"><strong jscontent=\"hostName\" jstcache=\"27\">cybertrusty.com</strong> redirected you too many times.</div>\n  </div>\n\n\n<script jstcache=\"0\">(function(){function l(a,b,c){return Function.prototype.call.apply(Array.prototype.slice,arguments)}function m(a,b,c){var e=l(arguments,2);return function(){return b.apply(a,e)}}function n(a,b){var c=new p(b);for(c.h=[a];c.h.length;){var e=c,d=c.h.shift();e.i(d);for(d=d.firstChild;d;d=d.nextSibling)1==d.nodeType&&e.h.push(d)}}function p(a){this.i=a}function q(a){a.style.display=\"\"}function r(a){a.style.display=\"none\"};var t=/\\s*;\\s*/;function u(a,b){this.l.apply(this,arguments)}u.prototype.l=function(a,b){this.a||(this.a={});if(b){var c=this.a,e=b.a;for(d in e)c[d]=e[d]}else{var d=this.a;e=v;for(c in e)d[c]=e[c]}this.a.$this=a;this.a.$context=this;this.f=\"undefined\"!=typeof a&&null!=a?a:\"\";b||(this.a.$top=this.f)};var v={$default:null},w=[];function x(a){for(var b in a.a)delete a.a[b];a.f=null;w.push(a)}function y(a,b,c){try{return b.call(c,a.a,a.f)}catch(e){return v.$default}}\nu.prototype.clone=function(a,b,c){if(0<w.length){var e=w.pop();u.call(e,a,this);a=e}else a=new u(a,this);a.a.$index=b;a.a.$count=c;return a};var z;window.trustedTypes&&(z=trustedTypes.createPolicy(\"jstemplate\",{createScript:function(a){return a}}));var A={};function B(a){if(!A[a])try{var b=\"(function(a_, b_) { with (a_) with (b_) return \"+a+\" })\",c=window.trustedTypes?z.createScript(b):b;A[a]=window.eval(c)}catch(e){}return A[a]}\nfunction E(a){var b=[];a=a.split(t);for(var c=0,e=a.length;c<e;++c){var d=a[c].indexOf(\":\");if(!(0>d)){var g=a[c].substr(0,d).replace(/^\\s+/,\"\").replace(/\\s+$/,\"\");d=B(a[c].substr(d+1));b.push(g,d)}}return b};function F(){}var G=0,H={0:{}},I={},J={},K=[];function L(a){a.__jstcache||n(a,function(b){M(b)})}var N=[[\"jsselect\",B],[\"jsdisplay\",B],[\"jsvalues\",E],[\"jsvars\",E],[\"jseval\",function(a){var b=[];a=a.split(t);for(var c=0,e=a.length;c<e;++c)if(a[c]){var d=B(a[c]);b.push(d)}return b}],[\"transclude\",function(a){return a}],[\"jscontent\",B],[\"jsskip\",B]];\nfunction M(a){if(a.__jstcache)return a.__jstcache;var b=a.getAttribute(\"jstcache\");if(null!=b)return a.__jstcache=H[b];b=K.length=0;for(var c=N.length;b<c;++b){var e=N[b][0],d=a.getAttribute(e);J[e]=d;null!=d&&K.push(e+\"=\"+d)}if(0==K.length)return a.setAttribute(\"jstcache\",\"0\"),a.__jstcache=H[0];var g=K.join(\"&\");if(b=I[g])return a.setAttribute(\"jstcache\",b),a.__jstcache=H[b];var h={};b=0;for(c=N.length;b<c;++b){d=N[b];e=d[0];var f=d[1];d=J[e];null!=d&&(h[e]=f(d))}b=\"\"+ ++G;a.setAttribute(\"jstcache\",\nb);H[b]=h;I[g]=b;return a.__jstcache=h}function P(a,b){a.j.push(b);a.o.push(0)}function Q(a){return a.c.length?a.c.pop():[]}\nF.prototype.g=function(a,b){var c=R(b),e=c.transclude;if(e)(c=S(e))?(b.parentNode.replaceChild(c,b),e=Q(this),e.push(this.g,a,c),P(this,e)):b.parentNode.removeChild(b);else if(c=c.jsselect){c=y(a,c,b);var d=b.getAttribute(\"jsinstance\");var g=!1;d&&(\"*\"==d.charAt(0)?(d=parseInt(d.substr(1),10),g=!0):d=parseInt(d,10));var h=null!=c&&\"object\"==typeof c&&\"number\"==typeof c.length;e=h?c.length:1;var f=h&&0==e;if(h)if(f)d?b.parentNode.removeChild(b):(b.setAttribute(\"jsinstance\",\"*0\"),r(b));else if(q(b),\nnull===d||\"\"===d||g&&d<e-1){g=Q(this);d=d||0;for(h=e-1;d<h;++d){var k=b.cloneNode(!0);b.parentNode.insertBefore(k,b);T(k,c,d);f=a.clone(c[d],d,e);g.push(this.b,f,k,x,f,null)}T(b,c,d);f=a.clone(c[d],d,e);g.push(this.b,f,b,x,f,null);P(this,g)}else d<e?(g=c[d],T(b,c,d),f=a.clone(g,d,e),g=Q(this),g.push(this.b,f,b,x,f,null),P(this,g)):b.parentNode.removeChild(b);else null==c?r(b):(q(b),f=a.clone(c,0,1),g=Q(this),g.push(this.b,f,b,x,f,null),P(this,g))}else this.b(a,b)};\nF.prototype.b=function(a,b){var c=R(b),e=c.jsdisplay;if(e){if(!y(a,e,b)){r(b);return}q(b)}if(e=c.jsvars)for(var d=0,g=e.length;d<g;d+=2){var h=e[d],f=y(a,e[d+1],b);a.a[h]=f}if(e=c.jsvalues)for(d=0,g=e.length;d<g;d+=2)if(f=e[d],h=y(a,e[d+1],b),\"$\"==f.charAt(0))a.a[f]=h;else if(\".\"==f.charAt(0)){f=f.substr(1).split(\".\");for(var k=b,O=f.length,C=0,U=O-1;C<U;++C){var D=f[C];k[D]||(k[D]={});k=k[D]}k[f[O-1]]=h}else f&&(\"boolean\"==typeof h?h?b.setAttribute(f,f):b.removeAttribute(f):b.setAttribute(f,\"\"+h));\nif(e=c.jseval)for(d=0,g=e.length;d<g;++d)y(a,e[d],b);e=c.jsskip;if(!e||!y(a,e,b))if(c=c.jscontent){if(c=\"\"+y(a,c,b),b.innerHTML!=c){for(;b.firstChild;)e=b.firstChild,e.parentNode.removeChild(e);b.appendChild(this.m.createTextNode(c))}}else{c=Q(this);for(e=b.firstChild;e;e=e.nextSibling)1==e.nodeType&&c.push(this.g,a,e);c.length&&P(this,c)}};function R(a){if(a.__jstcache)return a.__jstcache;var b=a.getAttribute(\"jstcache\");return b?a.__jstcache=H[b]:M(a)}\nfunction S(a,b){var c=document;if(b){var e=c.getElementById(a);if(!e){e=b();var d=c.getElementById(\"jsts\");d||(d=c.createElement(\"div\"),d.id=\"jsts\",r(d),d.style.position=\"absolute\",c.body.appendChild(d));var g=c.createElement(\"div\");d.appendChild(g);g.innerHTML=e;e=c.getElementById(a)}c=e}else c=c.getElementById(a);return c?(L(c),c=c.cloneNode(!0),c.removeAttribute(\"id\"),c):null}function T(a,b,c){c==b.length-1?a.setAttribute(\"jsinstance\",\"*\"+c):a.setAttribute(\"jsinstance\",\"\"+c)};window.jstGetTemplate=S;window.JsEvalContext=u;window.jstProcess=function(a,b){var c=new F;L(b);c.m=b?9==b.nodeType?b:b.ownerDocument||document:document;var e=m(c,c.g,a,b),d=c.j=[],g=c.o=[];c.c=[];e();for(var h,f,k;d.length;)h=d[d.length-1],e=g[g.length-1],e>=h.length?(e=c,f=d.pop(),f.length=0,e.c.push(f),g.pop()):(f=h[e++],k=h[e++],h=h[e++],g[g.length-1]=e,f.call(c,k,h))};\n})()</script><script jstcache=\"0\">// Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * @fileoverview This file defines a singleton which provides access to all data\n * that is available as soon as the page's resources are loaded (before DOM\n * content has finished loading). This data includes both localized strings and\n * any data that is important to have ready from a very early stage (e.g. things\n * that must be displayed right away).\n *\n * Note that loadTimeData is not guaranteed to be consistent between page\n * refreshes (https://crbug.com/740629) and should not contain values that might\n * change if the page is re-opened later.\n */\n\n/** @type {!LoadTimeData} */\n// eslint-disable-next-line no-var\nvar loadTimeData;\n\nclass LoadTimeData {\n  constructor() {\n    /** @type {?Object} */\n    this.data_ = null;\n  }\n\n  /**\n   * Sets the backing object.\n   *\n   * Note that there is no getter for |data_| to discourage abuse of the form:\n   *\n   *     var value = loadTimeData.data()['key'];\n   *\n   * @param {Object} value The de-serialized page data.\n   */\n  set data(value) {\n    expect(!this.data_, 'Re-setting data.');\n    this.data_ = value;\n  }\n\n  /**\n   * @param {string} id An ID of a value that might exist.\n   * @return {boolean} True if |id| is a key in the dictionary.\n   */\n  valueExists(id) {\n    return this.data_ ? id in this.data_ : false;\n  }\n\n  /**\n   * Fetches a value, expecting that it exists.\n   * @param {string} id The key that identifies the desired value.\n   * @return {*} The corresponding value.\n   */\n  getValue(id) {\n    expect(this.data_, 'No data. Did you remember to include strings.js?');\n    const value = this.data_[id];\n    expect(typeof value !== 'undefined', 'Could not find value for ' + id);\n    return value;\n  }\n\n  /**\n   * As above, but also makes sure that the value is a string.\n   * @param {string} id The key that identifies the desired string.\n   * @return {string} The corresponding string value.\n   */\n  getString(id) {\n    const value = this.getValue(id);\n    expectIsType(id, value, 'string');\n    return /** @type {string} */ (value);\n  }\n\n  /**\n   * Returns a formatted localized string where $1 to $9 are replaced by the\n   * second to the tenth argument.\n   * @param {string} id The ID of the string we want.\n   * @param {...(string|number)} var_args The extra values to include in the\n   *     formatted output.\n   * @return {string} The formatted string.\n   */\n  getStringF(id, var_args) {\n    const value = this.getString(id);\n    if (!value) {\n      return '';\n    }\n\n    const args = Array.prototype.slice.call(arguments);\n    args[0] = value;\n    return this.substituteString.apply(this, args);\n  }\n\n  /**\n   * Returns a formatted localized string where $1 to $9 are replaced by the\n   * second to the tenth argument. Any standalone $ signs must be escaped as\n   * $$.\n   * @param {string} label The label to substitute through.\n   *     This is not an resource ID.\n   * @param {...(string|number)} var_args The extra values to include in the\n   *     formatted output.\n   * @return {string} The formatted string.\n   */\n  substituteString(label, var_args) {\n    const varArgs = arguments;\n    return label.replace(/\\$(.|$|\\n)/g, function(m) {\n      expect(m.match(/\\$[$1-9]/), 'Unescaped $ found in localized string.');\n      return m === '$$' ? '$' : varArgs[m[1]];\n    });\n  }\n\n  /**\n   * Returns a formatted string where $1 to $9 are replaced by the second to\n   * tenth argument, split apart into a list of pieces describing how the\n   * substitution was performed. Any standalone $ signs must be escaped as $$.\n   * @param {string} label A localized string to substitute through.\n   *     This is not an resource ID.\n   * @param {...(string|number)} var_args The extra values to include in the\n   *     formatted output.\n   * @return {!Array<!{value: string, arg: (null|string)}>} The formatted\n   *     string pieces.\n   */\n  getSubstitutedStringPieces(label, var_args) {\n    const varArgs = arguments;\n    // Split the string by separately matching all occurrences of $1-9 and of\n    // non $1-9 pieces.\n    const pieces = (label.match(/(\\$[1-9])|(([^$]|\\$([^1-9]|$))+)/g) ||\n                    []).map(function(p) {\n      // Pieces that are not $1-9 should be returned after replacing $$\n      // with $.\n      if (!p.match(/^\\$[1-9]$/)) {\n        expect(\n            (p.match(/\\$/g) || []).length % 2 === 0,\n            'Unescaped $ found in localized string.');\n        return {value: p.replace(/\\$\\$/g, '$'), arg: null};\n      }\n\n      // Otherwise, return the substitution value.\n      return {value: varArgs[p[1]], arg: p};\n    });\n\n    return pieces;\n  }\n\n  /**\n   * As above, but also makes sure that the value is a boolean.\n   * @param {string} id The key that identifies the desired boolean.\n   * @return {boolean} The corresponding boolean value.\n   */\n  getBoolean(id) {\n    const value = this.getValue(id);\n    expectIsType(id, value, 'boolean');\n    return /** @type {boolean} */ (value);\n  }\n\n  /**\n   * As above, but also makes sure that the value is an integer.\n   * @param {string} id The key that identifies the desired number.\n   * @return {number} The corresponding number value.\n   */\n  getInteger(id) {\n    const value = this.getValue(id);\n    expectIsType(id, value, 'number');\n    expect(value === Math.floor(value), 'Number isn\\'t integer: ' + value);\n    return /** @type {number} */ (value);\n  }\n\n  /**\n   * Override values in loadTimeData with the values found in |replacements|.\n   * @param {Object} replacements The dictionary object of keys to replace.\n   */\n  overrideValues(replacements) {\n    expect(\n        typeof replacements === 'object',\n        'Replacements must be a dictionary object.');\n    for (const key in replacements) {\n      this.data_[key] = replacements[key];\n    }\n  }\n\n  /**\n   * Reset loadTimeData's data. Should only be used in tests.\n   * @param {?Object} newData The data to restore to, when null restores to\n   *    unset state.\n   */\n  resetForTesting(newData = null) {\n    this.data_ = newData;\n  }\n\n  /**\n   * @return {boolean} Whether loadTimeData.data has been set.\n   */\n  isInitialized() {\n    return this.data_ !== null;\n  }\n}\n\n  /**\n   * Checks condition, throws error message if expectation fails.\n   * @param {*} condition The condition to check for truthiness.\n   * @param {string} message The message to display if the check fails.\n   */\n  function expect(condition, message) {\n    if (!condition) {\n      throw new Error(\n          'Unexpected condition on ' + document.location.href + ': ' + message);\n    }\n  }\n\n  /**\n   * Checks that the given value has the given type.\n   * @param {string} id The id of the value (only used for error message).\n   * @param {*} value The value to check the type on.\n   * @param {string} type The type we expect |value| to be.\n   */\n  function expectIsType(id, value, type) {\n    expect(\n        typeof value === type, '[' + value + '] (' + id + ') is not a ' + type);\n  }\n\n  expect(!loadTimeData, 'should only include this file once');\n  loadTimeData = new LoadTimeData();\n\n  // Expose |loadTimeData| directly on |window|, since within a JS module the\n  // scope is local and not all files have been updated to import the exported\n  // |loadTimeData| explicitly.\n  window.loadTimeData = loadTimeData;\n\n  console.warn('crbug/1173575, non-JS module files deprecated.');</script><script jstcache=\"0\">const pageData = {\"details\":\"Details\",\"errorCode\":\"ERR_TOO_MANY_REDIRECTS\",\"fontfamily\":\"system-ui, sans-serif\",\"fontsize\":\"75%\",\"heading\":{\"hostName\":\"cybertrusty.com\",\"msg\":\"This page isn’t working right now\"},\"hideDetails\":\"Hide details\",\"iconClass\":\"icon-page-error\",\"is_windows_xbox_sku\":\"false\",\"language\":\"en\",\"suggestionsDetails\":[],\"suggestionsSummaryList\":[{\"learnMoreUrl\":\"https://go.microsoft.com/fwlink/?linkid=2112473\",\"summary\":\"To fix this issue, try \\u003Ca jsvalues=\\\"href:learnMoreUrl\\\" id=\\\"clear-cookies-link\\\">clearing your cookies\\u003C/a>.\"}],\"summary\":{\"failedUrl\":\"https://cybertrusty.com/\",\"hostName\":\"cybertrusty.com\",\"msg\":\"\\u003Cstrong jscontent=\\\"hostName\\\">\\u003C/strong> redirected you too many times.\"},\"textdirection\":\"ltr\",\"title\":\"cybertrusty.com\"};loadTimeData.data = pageData;var tp = document.getElementById('t');jstProcess(new JsEvalContext(pageData), tp);</script></body>"
outerText: "This page isn’t working right now\n\ncybertrusty.com redirected you too many times.\n\n

There is an “n” in front of the URL, not sure if that causes an issue.

Am I running more than one instance of caddy, is it possible, how to check?

$ sudo docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED       STATUS                 PORTS                                                                                NAMES
b93a8ea969f9   caddy:2                     "caddy run --config …"   8 hours ago   Up 5 minutes           0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 2019/tcp   caddy
fed36b32a25d   vaultwarden/server:latest   "/usr/bin/dumb-init …"   8 hours ago   Up 8 hours (healthy)   127.0.0.1:3012->3012/tcp, 127.0.0.1:8080->80/tcp                                     vaultwarden

That’s exactly what I was mentioning as being the problem, i.e. infinite redirects. The Location header is what tells clients “try again at this URL”.

That’s a \n which is an escaped newline character. That’s normal.

Probably not. Only one program can bind to a particular port at a time, so a second one would fail to start.

What’s in your Caddy container’s logs? Turn on the debug global option by adding this at the top of your Caddyfile:

{
	debug
}

It’s probably a misconfiguration in vaultwarden making it perform a redirect. Make sure it’s configured to accept HTTP requests and not redirect to HTTPS.

1 Like

I rebuilt the VM following a different guide but still the same error. I enabled debug.

Here is my vaulwarden docker run.


sudo docker run -d --name vaultwarden -v /srv/vw-data:/data -e WEBSOCKET_ENABLED=true -p 127.0.0.1:8080:80 -p 127.0.0.1:3012:3012 --restart on-failure vaultwarden/server:latest

Here is the debug logs

{"level":"debug","ts":1660000676.4065933,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"0.0.0.0:80","duration":0.000746081,"request":{"remote_ip":"174.193.132.246","remote_port":"1327","proto":"HTTP/2.0","method":"GET","host":"cybertrusty.com","uri":"/","headers":{"User-Agent":["Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Mobile/15E148 Safari/604.1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],"X-Forwarded-For":["174.193.132.246"],"X-Forwarded-Proto":["https"],"X-Forwarded-Host":["cybertrusty.com"],"Accept-Language":["en-US,en;q=0.9"],"Accept-Encoding":["gzip, deflate, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"cybertrusty.com"}},"headers":{"Location":["https://cybertrusty.com/"],"Server":["Caddy"],"Date":["Mon, 08 Aug 2022 23:17:56 GMT"],"Content-Length":["0"]},"status":308}
{"level":"debug","ts":1660000676.5058365,"logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"0.0.0.0:80","total_upstreams":1}
{"level":"debug","ts":1660000676.506595,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"0.0.0.0:80","duration":0.00068988,"request":{"remote_ip":"174.193.132.246","remote_port":"1327","proto":"HTTP/2.0","method":"GET","host":"cybertrusty.com","uri":"/","headers":{"X-Forwarded-Proto":["https"],"X-Forwarded-Host":["cybertrusty.com"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],"Accept-Language":["en-US,en;q=0.9"],"Accept-Encoding":["gzip, deflate, br"],"User-Agent":["Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Mobile/15E148 Safari/604.1"],"X-Forwarded-For":["174.193.132.246"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"cybertrusty.com"}},"headers":{"Location":["https://cybertrusty.com/"],"Server":["Caddy"],"Date":["Mon, 08 Aug 2022 23:17:56 GMT"],"Content-Length":["0"]},"status":308}
{"level":"debug","ts":1660000676.6059182,"logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"0.0.0.0:80","total_upstreams":1}
{"level":"debug","ts":1660000676.6066442,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"0.0.0.0:80","duration":0.00063515,"request":{"remote_ip":"174.193.132.246","remote_port":"1327","proto":"HTTP/2.0","method":"GET","host":"cybertrusty.com","uri":"/","headers":{"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],"Accept-Language":["en-US,en;q=0.9"],"Accept-Encoding":["gzip, deflate, br"],"X-Forwarded-For":["174.193.132.246"],"X-Forwarded-Proto":["https"],"X-Forwarded-Host":["cybertrusty.com"],"User-Agent":["Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Mobile/15E148 Safari/604.1"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"cybertrusty.com"}},"headers":{"Location":["https://cybertrusty.com/"],"Server":["Caddy"],"Date":["Mon, 08 Aug 2022 23:17:56 GMT"],"Content-Length":["0"]},"status":308}

my caddy run

sudo docker run -d -p 80:80 -p 443:443 --name caddy -v /etc/Caddyfile:/etc/caddy/Caddyfile -v /etc/caddy:/root/.local/share/caddy --restart on-failure caddy:latest

Here is my caddyfile

{
    debug
}

cybertrusty.com {
encode gzip

# The negotiation endpoint is also proxied to Rocket
reverse_proxy /notifications/hub/negotiate 0.0.0.0:80

# Notifications redirected to the websockets server
reverse_proxy /notifications/hub 0.0.0.0:3012

# Send all other traffic to the regular Vaultwarden endpoint
reverse_proxy 0.0.0.0:80
}

I changed my caddyfile to look like this (changing 0.0.0.0 to vaultwarden)

{
    debug
}

cybertrusty.com {
encode gzip

# The negotiation endpoint is also proxied to Rocket
reverse_proxy /notifications/hub/negotiate 0.0.0.0:80

# Notifications redirected to the websockets server
reverse_proxy /notifications/hub 0.0.0.0:3012

# Send all other traffic to the regular Vaultwarden endpoint
reverse_proxy vaultwarden:80
}

My error now changed to 502 (bad gateway), I guess it’s progress?

Can’t believe I actually got it to work, I had to do

docker-compose up

after I cleaned up multiple docker compose instances for vaultwarden

Thanks a lot for your help, really appreciated. Let’s see how it runs for the next few days.

1 Like

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