diff --git a/404.html b/404.html index 289d0587..98bab290 100644 --- a/404.html +++ b/404.html @@ -9,7 +9,7 @@ - + diff --git a/assets/js/d768dc0f.8e1de618.js b/assets/js/d768dc0f.374d3e8d.js similarity index 75% rename from assets/js/d768dc0f.8e1de618.js rename to assets/js/d768dc0f.374d3e8d.js index 54919be7..9fa99979 100644 --- a/assets/js/d768dc0f.8e1de618.js +++ b/assets/js/d768dc0f.374d3e8d.js @@ -1 +1 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5882],{475:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var o=r(5893),t=r(1151);const i={sidebar_position:40,title:"Self-Hosting Guide for Linux",sidebar_label:"Linux"},s=void 0,l={id:"guides/self-hosting/linux/index",title:"Self-Hosting Guide for Linux",description:"Walkthrough Video",source:"@site/../docs/guides/self-hosting/linux/index.mdx",sourceDirName:"guides/self-hosting/linux",slug:"/guides/self-hosting/linux/",permalink:"/docs/guides/self-hosting/linux/",draft:!1,unlisted:!1,editUrl:"https://github.com/openziti/zrok/blob/main/docs/../docs/guides/self-hosting/linux/index.mdx",tags:[],version:"current",sidebarPosition:40,frontMatter:{sidebar_position:40,title:"Self-Hosting Guide for Linux",sidebar_label:"Linux"},sidebar:"tutorialSidebar",previous:{title:"Self Hosting",permalink:"/docs/category/self-hosting"},next:{title:"NGINX TLS",permalink:"/docs/guides/self-hosting/linux/nginx"}},c={},d=[{value:"Walkthrough Video",id:"walkthrough-video",level:2},{value:"Before you Begin",id:"before-you-begin",level:2},{value:"OpenZiti",id:"openziti",level:2},{value:"Install zrok",id:"install-zrok",level:2},{value:"Configure the Controller",id:"configure-the-controller",level:2},{value:"Environment Variables",id:"environment-variables",level:2},{value:"Bootstrap OpenZiti for zrok",id:"bootstrap-openziti-for-zrok",level:2},{value:"Run zrok Controller",id:"run-zrok-controller",level:2},{value:"Create zrok Frontend",id:"create-zrok-frontend",level:2},{value:"Configure the Public Frontend",id:"configure-the-public-frontend",level:2},{value:"Start Public Frontend",id:"start-public-frontend",level:2},{value:"Create a User Account",id:"create-a-user-account",level:2},{value:"Invite Additional Users",id:"invite-additional-users",level:2},{value:"Enable Your Environment",id:"enable-your-environment",level:2}];function a(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h2,{id:"walkthrough-video",children:"Walkthrough Video"}),"\n",(0,o.jsx)("iframe",{width:"100%",height:"315",src:"https://www.youtube.com/embed/870A5dke_u4",title:"YouTube video player",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowfullscreen:!0}),"\n",(0,o.jsx)(n.h2,{id:"before-you-begin",children:"Before you Begin"}),"\n",(0,o.jsxs)(n.p,{children:["This will get you up and running with a self-hosted instance of ",(0,o.jsx)(n.code,{children:"zrok"}),". I'll assume you have the following:"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"a Linux server with a public IP"}),"\n",(0,o.jsxs)(n.li,{children:["a wildcard DNS record like ",(0,o.jsx)(n.code,{children:"*.zrok.quigley.com"})," that resolves to the server IP"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"openziti",children:"OpenZiti"}),"\n",(0,o.jsxs)(n.p,{children:['OpenZiti (a.k.a. "Ziti") provides secure network backhaul for ',(0,o.jsx)(n.code,{children:"zrok"})," public and private shares. You need a Ziti Controller and a Ziti Router. You can run everything on the same Linux VPS."]}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Install the Ziti Controller package by following the ",(0,o.jsx)(n.a,{href:"https://openziti.io/docs/category/deployments",children:"Linux controller deployment guide"}),"."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Ensure your answer file (",(0,o.jsx)(n.code,{children:"/opt/openziti/etc/controller/bootstrap.env"}),") has the FQDN of your Linux server and an admin password defined."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Ensure your firewall allows the controller port from the answer file."}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Start the controller service (",(0,o.jsx)(n.code,{children:"ziti-controller.service"}),") and check the status."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Log in to the Ziti Controller"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ziti edge login localhost:1280 -u admin -p \n"})}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Administratively Create a Ziti Router"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'ziti edge create edge-router "router1" -o /tmp/router1.jwt\n'})}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Install the Ziti Router package by following ",(0,o.jsx)(n.a,{href:"https://openziti.io/docs/category/deployments",children:"the Linux router deployment guide"}),"."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Ensure your answer file (",(0,o.jsx)(n.code,{children:"/opt/openziti/etc/router/bootstrap.env"}),") has the FQDN of your Linux server for both controller and router addresses and the enrollment token from the previous step."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Ensure your firewall allows the router port from the answer file."}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Start the router service (",(0,o.jsx)(n.code,{children:"ziti-router.service"}),") and check the status."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Verify the new router is online."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ziti edge list edge-routers\n"})}),"\n"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"install-zrok",children:"Install zrok"}),"\n",(0,o.jsxs)(n.p,{children:["Debian and RPM packages are available for ",(0,o.jsx)(n.code,{children:"zrok"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"sudo apt install zrok\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Follow ",(0,o.jsx)(n.a,{href:"/docs/guides/install/linux",children:"the Linux installation guide"})," to install the ",(0,o.jsx)(n.code,{children:"zrok"})," package from the repository or manually install the binary for your platform."]}),"\n",(0,o.jsx)(n.h2,{id:"configure-the-controller",children:"Configure the Controller"}),"\n",(0,o.jsxs)(n.p,{children:["Create a ",(0,o.jsx)(n.code,{children:"zrok"})," controller configuration file in ",(0,o.jsx)(n.code,{children:"etc/ctrl.yml"}),". The controller can terminate TLS or you may front the server with a reverse proxy that continually renews the necessary wildcard certificate (e.g., Caddy w/ a DNS provider plugin). This example will expose the non-TLS listener for the controller."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# _____ __ ___ | | __\n# |_ / \'__/ _ \\| |/ /\n# / /| | | (_) | <\n# /___|_| \\___/|_|\\_\\\n# controller configuration\n\nv: 3\n\nadmin:\n # generate these admin tokens from a source of randomness, e.g. \n # LC_ALL=C tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c32\n secrets:\n - Q8V0LqnNb5wNX9kE1fgQ0H6VlcvJybB1 # be sure to change this!\n\nendpoint:\n host: 0.0.0.0\n port: 18080\n\ninvites:\n invites_open: true\n\nstore:\n path: zrok.db\n type: sqlite3\n\nziti:\n api_endpoint: "https://127.0.0.1:1280"\n username: admin\n password: "XO0xHp75uuyeireO2xmmVlK91T7B9fpD"\n\n# you can use certbot to renew the wildcard cert for the controller with a DNS provider API token or front this `zrok` # controller with Caddy\n#tls:\n# cert_path: "/Path/To/Cert/zrok.crt"\n# key_path: "/Path/To/Cert/zrok.key"\n\n'})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"admin"})," section defines privileged administrative credentials and must be set in the ",(0,o.jsx)(n.code,{children:"ZROK_ADMIN_TOKEN"})," environment variable in shells where you want to run ",(0,o.jsx)(n.code,{children:"zrok admin"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"endpoint"})," section defines where your ",(0,o.jsx)(n.code,{children:"zrok"})," controller will listen."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"store"})," section defines the local ",(0,o.jsx)(n.code,{children:"sqlite3"})," database used by the controller."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"ziti"})," section defines how the ",(0,o.jsx)(n.code,{children:"zrok"})," controller should communicate with your OpenZiti installation. When using the OpenZiti quickstart, an administrative password will be generated; the ",(0,o.jsx)(n.code,{children:"password"})," in the ",(0,o.jsx)(n.code,{children:"ziti"})," stanza should reflect this password."]}),"\n",(0,o.jsxs)(n.admonition,{type:"note",children:[(0,o.jsxs)(n.p,{children:["Be sure to see the ",(0,o.jsxs)(n.a,{target:"_blank","data-noBrokenLinkCheck":!0,href:r(7996).Z+"",children:["reference configuration at ",(0,o.jsx)(n.code,{children:"etc/ctrl.yml"})]})," for the complete documentation of the current configuration file format for the ",(0,o.jsx)(n.code,{children:"zrok"})," controller and service instance components."]}),(0,o.jsxs)(n.p,{children:["See the separate guides on ",(0,o.jsx)(n.a,{href:"/docs/guides/self-hosting/metrics-and-limits/configuring-metrics",children:"configuring metrics"})," and ",(0,o.jsx)(n.a,{href:"/docs/guides/self-hosting/metrics-and-limits/configuring-limits",children:"configuring limits"})," for details about both of these specialized areas of service instance configuration."]})]}),"\n",(0,o.jsx)(n.h2,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok"})," binaries are configured to work with the global ",(0,o.jsx)(n.code,{children:"zrok.io"})," service, and default to using ",(0,o.jsx)(n.code,{children:"api.zrok.io"})," as the endpoint for communicating with the service."]}),"\n",(0,o.jsxs)(n.p,{children:["To work with a self-hosted ",(0,o.jsx)(n.code,{children:"zrok"})," deployment, you'll need to set the ",(0,o.jsx)(n.code,{children:"ZROK_API_ENDPOINT"})," environment variable to point to the address where your ",(0,o.jsx)(n.code,{children:"zrok"})," controller will be listening, according to ",(0,o.jsx)(n.code,{children:"endpoint"})," in the configuration file above."]}),"\n",(0,o.jsx)(n.p,{children:"In my case, I've set:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"export ZROK_API_ENDPOINT=http://127.0.0.1:18080\n"})}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsxs)(n.a,{href:"/docs/guides/self-hosting/instance-configuration",children:["Read more about configuring your self-hosted ",(0,o.jsx)(n.code,{children:"zrok"})," instance"]}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"bootstrap-openziti-for-zrok",children:"Bootstrap OpenZiti for zrok"}),"\n",(0,o.jsxs)(n.p,{children:["With your OpenZiti network running and your configuration saved to a local file (I refer to mine as ",(0,o.jsx)(n.code,{children:"etc/ctrl.yml"})," in these examples), you're ready to bootstrap the Ziti network."]}),"\n",(0,o.jsxs)(n.p,{children:["Use the ",(0,o.jsx)(n.code,{children:"zrok admin bootstrap"})," command to bootstrap like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok admin bootstrap etc/ctrl.yml\n[ 0.002] INFO main.(*adminBootstrap).run: {\n\t...\n}\n[ 0.002] INFO zrok/controller/store.Open: database connected\n[ 0.006] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\n[ 0.006] INFO zrok/controller.Bootstrap: connecting to the ziti edge management api\n[ 0.039] INFO zrok/controller.Bootstrap: creating identity for controller ziti access\n[ 0.071] INFO zrok/controller.Bootstrap: controller identity: jKd8AINSz\n[ 0.082] INFO zrok/controller.assertIdentity: asserted identity 'jKd8AINSz'\n[ 0.085] INFO zrok/controller.assertErpForIdentity: asserted erps for 'ctrl' (jKd8AINSz)\n[ 0.085] INFO zrok/controller.Bootstrap: creating identity for frontend ziti access\n[ 0.118] INFO zrok/controller.Bootstrap: frontend identity: sqJRAINSiB\n[ 0.119] INFO zrok/controller.assertIdentity: asserted identity 'sqJRAINSiB'\n[ 0.120] INFO zrok/controller.assertErpForIdentity: asserted erps for 'frontend' (sqJRAINSiB)\n[ 0.120] WARNING zrok/controller.Bootstrap: missing public frontend for ziti id 'sqJRAINSiB'; please use 'zrok admin create frontend sqJRAINSiB public https://{token}.your.dns.name' to create a frontend instance\n[ 0.123] INFO zrok/controller.assertZrokProxyConfigType: found 'zrok.proxy.v1' config type with id '33CyjNbIepkXHN5VzGDA8L'\n[ 0.124] INFO zrok/controller.assertMetricsService: creating 'metrics' service\n[ 0.126] INFO zrok/controller.assertMetricsService: asserted 'metrics' service (5RpPZZ7T8bZf1ENjwGiPc3)\n[ 0.128] INFO zrok/controller.assertMetricsSerp: creating 'metrics' serp\n[ 0.130] INFO zrok/controller.assertMetricsSerp: asserted 'metrics' serp\n[ 0.134] INFO zrok/controller.assertCtrlMetricsBind: creating 'ctrl-metrics-bind' service policy\n[ 0.135] INFO zrok/controller.assertCtrlMetricsBind: asserted 'ctrl-metrics-bind' service policy\n[ 0.138] INFO zrok/controller.assertFrontendMetricsDial: creating 'frontend-metrics-dial' service policy\n[ 0.140] INFO zrok/controller.assertFrontendMetricsDial: asserted 'frontend-metrics-dial' service policy\n[ 0.140] INFO main.(*adminBootstrap).run: bootstrap complete!\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok admin bootstrap"})," command configures the ",(0,o.jsx)(n.code,{children:"zrok"})," database, the necessary OpenZiti identities, and all of the OpenZiti policies required to run a ",(0,o.jsx)(n.code,{children:"zrok"})," service."]}),"\n",(0,o.jsx)(n.p,{children:"Notice this warning:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"[ 0.120] WARNING zrok/controller.Bootstrap: missing public frontend for ziti id 'sqJRAINSiB'; please use 'zrok admin create frontend sqJRAINSiB public https://{token}.your.dns.name' to create a frontend instance\n"})}),"\n",(0,o.jsxs)(n.p,{children:["If you find it necessary to re-run the ",(0,o.jsx)(n.code,{children:"zrok admin bootstrap"})," command, you may need to add the ",(0,o.jsx)(n.code,{children:"--skip-frontend"})," flag to avoid re-creating the default ",(0,o.jsx)(n.code,{children:"public"})," frontend's Ziti identity and router policy."]}),"\n",(0,o.jsx)(n.h2,{id:"run-zrok-controller",children:"Run zrok Controller"}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok"}),' bootstrap process wants us to create a "public frontend" for our service. ',(0,o.jsx)(n.code,{children:"zrok"})," uses public frontends to allow users to specify where they would like public traffic to ingress from."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok admin create frontend"})," command requires a running ",(0,o.jsx)(n.code,{children:"zrok"})," controller, so let's start that up first:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok controller etc/ctrl.yml \n[ 0.003] INFO main.(*controllerCommand).run: {\n\t...\n}\n[ 0.016] INFO zrok/controller.inspectZiti: inspecting ziti controller configuration\n[ 0.048] INFO zrok/controller.findZrokProxyConfigType: found 'zrok.proxy.v1' config type with id '33CyjNbIepkXHN5VzGDA8L'\n[ 0.048] INFO zrok/controller/store.Open: database connected\n[ 0.048] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\n[ 0.049] INFO zrok/controller.(*metricsAgent).run: starting\n[ 0.064] INFO zrok/rest_server_zrok.setupGlobalMiddleware: configuring\n[ 0.064] INFO zrok/ui.StaticBuilder: building\n[ 0.065] INFO zrok/rest_server_zrok.(*Server).Logf: Serving zrok at http://[::]:18080\n[ 0.085] INFO zrok/controller.(*metricsAgent).listen: started\n"})}),"\n",(0,o.jsx)(n.h2,{id:"create-zrok-frontend",children:"Create zrok Frontend"}),"\n",(0,o.jsxs)(n.p,{children:["With our ",(0,o.jsx)(n.code,{children:"ZROK_ADMIN_TOKEN"})," and ",(0,o.jsx)(n.code,{children:"ZROK_API_ENDPOINT"})," environment variables set, we can create our public frontend like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok admin create frontend sqJRAINSiB public http://{token}.zrok.quigley.com:8080\n[ 0.037] INFO main.(*adminCreateFrontendCommand).run: created global public frontend 'WEirJNHVlcW9'\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The id of the frontend was emitted earlier in by the ",(0,o.jsx)(n.code,{children:"zrok"})," controller when we ran the bootstrap command. If you don't have that log message the you can find the id again with the ",(0,o.jsx)(n.code,{children:"ziti"})," CLI like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"# log in as admin (example)\nziti edge login localhost:1280 -u admin -p XO0xHp75uuyeireO2xmmVlK91T7B9fpD\n\n# list Ziti identities created by the quickstart and bootstrap\nziti edge list identities\n"})}),"\n",(0,o.jsx)(n.p,{children:'The id is shown for the frontend identity named "public."'}),"\n",(0,o.jsxs)(n.p,{children:["Nice work! The ",(0,o.jsx)(n.code,{children:"zrok"})," controller is fully configured now that you have created the ",(0,o.jsx)(n.code,{children:"zrok"})," frontend."]}),"\n",(0,o.jsx)(n.h2,{id:"configure-the-public-frontend",children:"Configure the Public Frontend"}),"\n",(0,o.jsxs)(n.p,{children:["Create an http frontend configuration file in ",(0,o.jsx)(n.code,{children:"etc/http-frontend.yml"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"v: 3\nhost_match: zrok.quigley.com\naddress: 0.0.0.0:8080\n"})}),"\n",(0,o.jsxs)(n.p,{children:["This frontend config file has a ",(0,o.jsx)(n.code,{children:"host_match"})," pattern that represents the DNS zone you're using with this instance of ",(0,o.jsx)(n.code,{children:"zrok"}),". Incoming HTTP requests with a matching ",(0,o.jsx)(n.code,{children:"Host"})," header will be handled by this frontend. You may also specify the interface address where the frontend will listen for public access requests."]}),"\n",(0,o.jsxs)(n.p,{children:["The frontend does not provide server TLS, but you may front the server with a reverse proxy. It is essential the reverse proxy forwards the ",(0,o.jsx)(n.code,{children:"Host"})," header supplied by the viewer. This example will expose the non-TLS listener for the frontend."]}),"\n",(0,o.jsxs)(n.p,{children:["You can also specify an ",(0,o.jsx)(n.code,{children:"oauth"})," configuration in this file, full details of are found in ",(0,o.jsx)(n.a,{href:"/docs/guides/self-hosting/oauth/configuring-oauth#configuring-your-public-frontend",children:"OAuth Public Frontend Configuration"}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"start-public-frontend",children:"Start Public Frontend"}),"\n",(0,o.jsx)(n.p,{children:"In another terminal window, run:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok access public etc/http-frontend.yml\n[ 0.002] INFO main.(*accessPublicCommand).run: {\n\t...\n}\n[ 0.002] INFO zrok/endpoints/public_frontend.newMetricsAgent: loaded 'public' identity\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok"})," frontend uses the ",(0,o.jsx)(n.code,{children:"public"})," identity created during the bootstrap process to securely access zrok backends. to provide public access for the ",(0,o.jsx)(n.code,{children:"zrok"})," deployment. It is expected that the configured listener for this frontend corresponds to the DNS template specified when creating the public frontend record above."]}),"\n",(0,o.jsx)(n.h2,{id:"create-a-user-account",children:"Create a User Account"}),"\n",(0,o.jsxs)(n.p,{children:["With our ",(0,o.jsx)(n.code,{children:"ZROK_ADMIN_TOKEN"})," and ",(0,o.jsx)(n.code,{children:"ZROK_API_ENDPOINT"})," environment variables set, we can create our first user account."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"zrok admin create account etc/ctrl.yml \n"})}),"\n",(0,o.jsx)(n.p,{children:"The output is the account token you will use to enable each device's zrok environment."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"SuGzRPjVDIcF\n"})}),"\n",(0,o.jsx)(n.h2,{id:"invite-additional-users",children:"Invite Additional Users"}),"\n",(0,o.jsxs)(n.p,{children:["Offer this onboarding method to your users if you have configured an email-sending service in your ",(0,o.jsx)(n.code,{children:"zrok"})," controller configuration."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok invite\nNew Email: user@domain.com\nConfirm Email: user@domain.com\ninvitation sent to 'user@domain.com'!\n"})}),"\n",(0,o.jsxs)(n.p,{children:["If you look at the console output from your ",(0,o.jsx)(n.code,{children:"zrok"})," controller, you'll see a message like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"[ 238.168] INFO zrok/controller.(*inviteHandler).Handle: account request for 'user@domain.com' has registration token 'U2Ewt1UCn3ql'\n"})}),"\n",(0,o.jsxs)(n.p,{children:["You can access your ",(0,o.jsx)(n.code,{children:"zrok"})," controller's registration UI by pointing a web browser at:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"http://localhost:18080/register/U2Ewt1UCn3ql\n"})}),"\n",(0,o.jsx)(n.p,{children:"The UI will ask you to set a password for your new account. Go ahead and do that."}),"\n",(0,o.jsx)(n.p,{children:"After doing that, I see the following output in my controller console:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"[ 516.778] INFO zrok/controller.(*registerHandler).Handle: created account 'user@domain.com' with token 'SuGzRPjVDIcF'\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Keep track of the token listed above (",(0,o.jsx)(n.code,{children:"SuGzRPjVDIcF"}),"). We'll use this to enable our shell for this ",(0,o.jsx)(n.code,{children:"zrok"})," deployment."]}),"\n",(0,o.jsx)(n.h2,{id:"enable-your-environment",children:"Enable Your Environment"}),"\n",(0,o.jsx)(n.p,{children:"On another device that can reach your Linux server by FQDN, configure the API endpoint and enable the environment with the account token you received when you created the first user account."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"export ZROK_API_ENDPOINT=https://zrok.quigley.com\n# or\nzrok config set apiEndpoint https://zrok.quigley.com\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"zrok enable SuGzRPjVDIcF\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"zrok environment '2AS1WZ3Sz' enabled for 'SuGzRPjVDIcF'\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"zrok status --secrets\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"Config:\n\n CONFIG VALUE SOURCE\n apiEndpoint https://zrok.quigley.com env\n\nEnvironment:\n\n PROPERTY VALUE\n Secret Token SuGzRPjVDIcF\n Ziti Identity 2AS1WZ3Sz\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Congratulations. You have a working ",(0,o.jsx)(n.code,{children:"zrok"})," environment!"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(a,{...e})}):a(e)}},7996:(e,n,r)=>{r.d(n,{Z:()=>o});const o=r.p+"assets/files/ctrl-8468281a3bbdbc5852c252b0af86a113.yml"},1151:(e,n,r)=>{r.d(n,{Z:()=>l,a:()=>s});var o=r(7294);const t={},i=o.createContext(t);function s(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[5882],{475:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var o=r(5893),t=r(1151);const i={sidebar_position:40,title:"Self-Hosting Guide for Linux",sidebar_label:"Linux"},s=void 0,l={id:"guides/self-hosting/linux/index",title:"Self-Hosting Guide for Linux",description:"Walkthrough Video",source:"@site/../docs/guides/self-hosting/linux/index.mdx",sourceDirName:"guides/self-hosting/linux",slug:"/guides/self-hosting/linux/",permalink:"/docs/guides/self-hosting/linux/",draft:!1,unlisted:!1,editUrl:"https://github.com/openziti/zrok/blob/main/docs/../docs/guides/self-hosting/linux/index.mdx",tags:[],version:"current",sidebarPosition:40,frontMatter:{sidebar_position:40,title:"Self-Hosting Guide for Linux",sidebar_label:"Linux"},sidebar:"tutorialSidebar",previous:{title:"Self Hosting",permalink:"/docs/category/self-hosting"},next:{title:"NGINX TLS",permalink:"/docs/guides/self-hosting/linux/nginx"}},c={},d=[{value:"Walkthrough Video",id:"walkthrough-video",level:2},{value:"Before you Begin",id:"before-you-begin",level:2},{value:"OpenZiti",id:"openziti",level:2},{value:"Install zrok",id:"install-zrok",level:2},{value:"Configure the Controller",id:"configure-the-controller",level:2},{value:"Environment Variables",id:"environment-variables",level:2},{value:"Bootstrap OpenZiti for zrok",id:"bootstrap-openziti-for-zrok",level:2},{value:"Run zrok Controller",id:"run-zrok-controller",level:2},{value:"Create zrok Frontend",id:"create-zrok-frontend",level:2},{value:"Configure the Public Frontend",id:"configure-the-public-frontend",level:2},{value:"Start Public Frontend",id:"start-public-frontend",level:2},{value:"Create a User Account",id:"create-a-user-account",level:2},{value:"Invite Additional Users",id:"invite-additional-users",level:2},{value:"Enable Your Environment",id:"enable-your-environment",level:2}];function a(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,t.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h2,{id:"walkthrough-video",children:"Walkthrough Video"}),"\n",(0,o.jsx)("iframe",{width:"100%",height:"315",src:"https://www.youtube.com/embed/870A5dke_u4",title:"YouTube video player",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowfullscreen:!0}),"\n",(0,o.jsx)(n.h2,{id:"before-you-begin",children:"Before you Begin"}),"\n",(0,o.jsxs)(n.p,{children:["This will get you up and running with a self-hosted instance of ",(0,o.jsx)(n.code,{children:"zrok"}),". I'll assume you have the following:"]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"a Linux server with a public IP"}),"\n",(0,o.jsxs)(n.li,{children:["a wildcard DNS record like ",(0,o.jsx)(n.code,{children:"*.zrok.quigley.com"})," that resolves to the server IP"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"openziti",children:"OpenZiti"}),"\n",(0,o.jsxs)(n.p,{children:['OpenZiti (a.k.a. "Ziti") provides secure network backhaul for ',(0,o.jsx)(n.code,{children:"zrok"})," public and private shares. You need a Ziti Controller and a Ziti Router. You can run everything on the same Linux VPS."]}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Install the Ziti Controller package by following the ",(0,o.jsx)(n.a,{href:"https://openziti.io/docs/category/deployments",children:"Linux controller deployment guide"}),"."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Ensure your answer file (",(0,o.jsx)(n.code,{children:"/opt/openziti/etc/controller/bootstrap.env"}),") has the FQDN of your Linux server and an admin password defined."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Ensure your firewall allows the controller port from the answer file."}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Start the controller service (",(0,o.jsx)(n.code,{children:"ziti-controller.service"}),") and check the status."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Log in to the Ziti Controller"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ziti edge login localhost:1280 -u admin -p \n"})}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Administratively Create a Ziti Router"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'ziti edge create edge-router "router1" -o /tmp/router1.jwt\n'})}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Install the Ziti Router package by following ",(0,o.jsx)(n.a,{href:"https://openziti.io/docs/category/deployments",children:"the Linux router deployment guide"}),"."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Ensure your answer file (",(0,o.jsx)(n.code,{children:"/opt/openziti/etc/router/bootstrap.env"}),") has the FQDN of your Linux server for both controller and router addresses and the enrollment token from the previous step."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Ensure your firewall allows the router port from the answer file."}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsxs)(n.p,{children:["Start the router service (",(0,o.jsx)(n.code,{children:"ziti-router.service"}),") and check the status."]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:["\n",(0,o.jsx)(n.p,{children:"Verify the new router is online."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ziti edge list edge-routers\n"})}),"\n"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"install-zrok",children:"Install zrok"}),"\n",(0,o.jsxs)(n.p,{children:["Debian and RPM packages are available for ",(0,o.jsx)(n.code,{children:"zrok"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"sudo apt install zrok\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Follow ",(0,o.jsx)(n.a,{href:"/docs/guides/install/linux",children:"the Linux installation guide"})," to install the ",(0,o.jsx)(n.code,{children:"zrok"})," package from the repository or manually install the binary for your platform."]}),"\n",(0,o.jsx)(n.h2,{id:"configure-the-controller",children:"Configure the Controller"}),"\n",(0,o.jsxs)(n.p,{children:["Create a ",(0,o.jsx)(n.code,{children:"zrok"})," controller configuration file in ",(0,o.jsx)(n.code,{children:"etc/ctrl.yml"}),". The controller can terminate TLS or you may front the server with a reverse proxy that continually renews the necessary wildcard certificate (e.g., Caddy w/ a DNS provider plugin). This example will expose the non-TLS listener for the controller."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:'# _____ __ ___ | | __\n# |_ / \'__/ _ \\| |/ /\n# / /| | | (_) | <\n# /___|_| \\___/|_|\\_\\\n# controller configuration\n\nv: 3\n\nadmin:\n # generate these admin tokens from a source of randomness, e.g. \n # LC_ALL=C tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c32\n secrets:\n - Q8V0LqnNb5wNX9kE1fgQ0H6VlcvJybB1 # be sure to change this!\n\nendpoint:\n host: 0.0.0.0\n port: 18080\n\ninvites:\n invites_open: true\n\nstore:\n path: zrok.db\n type: sqlite3\n\nziti:\n api_endpoint: "https://127.0.0.1:1280"\n username: admin\n password: "XO0xHp75uuyeireO2xmmVlK91T7B9fpD"\n\n# you can use certbot to renew the wildcard cert for the controller with a DNS provider API token or front this `zrok` # controller with Caddy\n#tls:\n# cert_path: "/Path/To/Cert/zrok.crt"\n# key_path: "/Path/To/Cert/zrok.key"\n\n'})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"admin"})," section defines privileged administrative credentials and must be set in the ",(0,o.jsx)(n.code,{children:"ZROK_ADMIN_TOKEN"})," environment variable in shells where you want to run ",(0,o.jsx)(n.code,{children:"zrok admin"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"endpoint"})," section defines where your ",(0,o.jsx)(n.code,{children:"zrok"})," controller will listen."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"store"})," section defines the local ",(0,o.jsx)(n.code,{children:"sqlite3"})," database used by the controller."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"ziti"})," section defines how the ",(0,o.jsx)(n.code,{children:"zrok"})," controller should communicate with your OpenZiti installation. When using the OpenZiti quickstart, an administrative password will be generated; the ",(0,o.jsx)(n.code,{children:"password"})," in the ",(0,o.jsx)(n.code,{children:"ziti"})," stanza should reflect this password."]}),"\n",(0,o.jsxs)(n.admonition,{type:"note",children:[(0,o.jsxs)(n.p,{children:["Be sure to see the ",(0,o.jsxs)(n.a,{target:"_blank","data-noBrokenLinkCheck":!0,href:r(7996).Z+"",children:["reference configuration at ",(0,o.jsx)(n.code,{children:"etc/ctrl.yml"})]})," for the complete documentation of the current configuration file format for the ",(0,o.jsx)(n.code,{children:"zrok"})," controller and service instance components."]}),(0,o.jsxs)(n.p,{children:["See the separate guides on ",(0,o.jsx)(n.a,{href:"/docs/guides/self-hosting/metrics-and-limits/configuring-metrics",children:"configuring metrics"})," and ",(0,o.jsx)(n.a,{href:"/docs/guides/self-hosting/metrics-and-limits/configuring-limits",children:"configuring limits"})," for details about both of these specialized areas of service instance configuration."]})]}),"\n",(0,o.jsx)(n.h2,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok"})," binaries are configured to work with the global ",(0,o.jsx)(n.code,{children:"zrok.io"})," service, and default to using ",(0,o.jsx)(n.code,{children:"api.zrok.io"})," as the endpoint for communicating with the service."]}),"\n",(0,o.jsxs)(n.p,{children:["To work with a self-hosted ",(0,o.jsx)(n.code,{children:"zrok"})," deployment, you'll need to set the ",(0,o.jsx)(n.code,{children:"ZROK_API_ENDPOINT"})," environment variable to point to the address where your ",(0,o.jsx)(n.code,{children:"zrok"})," controller will be listening, according to ",(0,o.jsx)(n.code,{children:"endpoint"})," in the configuration file above."]}),"\n",(0,o.jsx)(n.p,{children:"In my case, I've set:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"export ZROK_API_ENDPOINT=http://127.0.0.1:18080\n"})}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsxs)(n.a,{href:"/docs/guides/self-hosting/instance-configuration",children:["Read more about configuring your self-hosted ",(0,o.jsx)(n.code,{children:"zrok"})," instance"]}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"bootstrap-openziti-for-zrok",children:"Bootstrap OpenZiti for zrok"}),"\n",(0,o.jsxs)(n.p,{children:["With your OpenZiti network running and your configuration saved to a local file (I refer to mine as ",(0,o.jsx)(n.code,{children:"etc/ctrl.yml"})," in these examples), you're ready to bootstrap the Ziti network."]}),"\n",(0,o.jsxs)(n.p,{children:["Use the ",(0,o.jsx)(n.code,{children:"zrok admin bootstrap"})," command to bootstrap like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok admin bootstrap etc/ctrl.yml\n[ 0.002] INFO main.(*adminBootstrap).run: {\n\t...\n}\n[ 0.002] INFO zrok/controller/store.Open: database connected\n[ 0.006] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\n[ 0.006] INFO zrok/controller.Bootstrap: connecting to the ziti edge management api\n[ 0.039] INFO zrok/controller.Bootstrap: creating identity for controller ziti access\n[ 0.071] INFO zrok/controller.Bootstrap: controller identity: jKd8AINSz\n[ 0.082] INFO zrok/controller.assertIdentity: asserted identity 'jKd8AINSz'\n[ 0.085] INFO zrok/controller.assertErpForIdentity: asserted erps for 'ctrl' (jKd8AINSz)\n[ 0.085] INFO zrok/controller.Bootstrap: creating identity for frontend ziti access\n[ 0.118] INFO zrok/controller.Bootstrap: frontend identity: sqJRAINSiB\n[ 0.119] INFO zrok/controller.assertIdentity: asserted identity 'sqJRAINSiB'\n[ 0.120] INFO zrok/controller.assertErpForIdentity: asserted erps for 'frontend' (sqJRAINSiB)\n[ 0.120] WARNING zrok/controller.Bootstrap: missing public frontend for ziti id 'sqJRAINSiB'; please use 'zrok admin create frontend sqJRAINSiB public https://{token}.your.dns.name' to create a frontend instance\n[ 0.123] INFO zrok/controller.assertZrokProxyConfigType: found 'zrok.proxy.v1' config type with id '33CyjNbIepkXHN5VzGDA8L'\n[ 0.124] INFO zrok/controller.assertMetricsService: creating 'metrics' service\n[ 0.126] INFO zrok/controller.assertMetricsService: asserted 'metrics' service (5RpPZZ7T8bZf1ENjwGiPc3)\n[ 0.128] INFO zrok/controller.assertMetricsSerp: creating 'metrics' serp\n[ 0.130] INFO zrok/controller.assertMetricsSerp: asserted 'metrics' serp\n[ 0.134] INFO zrok/controller.assertCtrlMetricsBind: creating 'ctrl-metrics-bind' service policy\n[ 0.135] INFO zrok/controller.assertCtrlMetricsBind: asserted 'ctrl-metrics-bind' service policy\n[ 0.138] INFO zrok/controller.assertFrontendMetricsDial: creating 'frontend-metrics-dial' service policy\n[ 0.140] INFO zrok/controller.assertFrontendMetricsDial: asserted 'frontend-metrics-dial' service policy\n[ 0.140] INFO main.(*adminBootstrap).run: bootstrap complete!\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok admin bootstrap"})," command configures the ",(0,o.jsx)(n.code,{children:"zrok"})," database, the necessary OpenZiti identities, and all of the OpenZiti policies required to run a ",(0,o.jsx)(n.code,{children:"zrok"})," service."]}),"\n",(0,o.jsx)(n.p,{children:"Notice this warning:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"[ 0.120] WARNING zrok/controller.Bootstrap: missing public frontend for ziti id 'sqJRAINSiB'; please use 'zrok admin create frontend sqJRAINSiB public https://{token}.your.dns.name' to create a frontend instance\n"})}),"\n",(0,o.jsxs)(n.p,{children:["If you find it necessary to re-run the ",(0,o.jsx)(n.code,{children:"zrok admin bootstrap"})," command, you may need to add the ",(0,o.jsx)(n.code,{children:"--skip-frontend"})," flag to avoid re-creating the default ",(0,o.jsx)(n.code,{children:"public"})," frontend's Ziti identity and router policy."]}),"\n",(0,o.jsx)(n.h2,{id:"run-zrok-controller",children:"Run zrok Controller"}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok"}),' bootstrap process wants us to create a "public frontend" for our service. ',(0,o.jsx)(n.code,{children:"zrok"})," uses public frontends to allow users to specify where they would like public traffic to ingress from."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok admin create frontend"})," command requires a running ",(0,o.jsx)(n.code,{children:"zrok"})," controller, so let's start that up first:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok controller etc/ctrl.yml \n[ 0.003] INFO main.(*controllerCommand).run: {\n\t...\n}\n[ 0.016] INFO zrok/controller.inspectZiti: inspecting ziti controller configuration\n[ 0.048] INFO zrok/controller.findZrokProxyConfigType: found 'zrok.proxy.v1' config type with id '33CyjNbIepkXHN5VzGDA8L'\n[ 0.048] INFO zrok/controller/store.Open: database connected\n[ 0.048] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\n[ 0.049] INFO zrok/controller.(*metricsAgent).run: starting\n[ 0.064] INFO zrok/rest_server_zrok.setupGlobalMiddleware: configuring\n[ 0.064] INFO zrok/ui.StaticBuilder: building\n[ 0.065] INFO zrok/rest_server_zrok.(*Server).Logf: Serving zrok at http://[::]:18080\n[ 0.085] INFO zrok/controller.(*metricsAgent).listen: started\n"})}),"\n",(0,o.jsx)(n.h2,{id:"create-zrok-frontend",children:"Create zrok Frontend"}),"\n",(0,o.jsxs)(n.p,{children:["With our ",(0,o.jsx)(n.code,{children:"ZROK_ADMIN_TOKEN"})," and ",(0,o.jsx)(n.code,{children:"ZROK_API_ENDPOINT"})," environment variables set, we can create our public frontend like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok admin create frontend sqJRAINSiB public http://{token}.zrok.quigley.com:8080\n[ 0.037] INFO main.(*adminCreateFrontendCommand).run: created global public frontend 'WEirJNHVlcW9'\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The id of the frontend was emitted earlier in by the ",(0,o.jsx)(n.code,{children:"zrok"})," controller when we ran the bootstrap command. If you don't have that log message the you can find the id again with the ",(0,o.jsx)(n.code,{children:"ziti"})," CLI like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"# log in as admin (example)\nziti edge login localhost:1280 -u admin -p XO0xHp75uuyeireO2xmmVlK91T7B9fpD\n\n# list Ziti identities created by the quickstart and bootstrap\nziti edge list identities\n"})}),"\n",(0,o.jsx)(n.p,{children:'The id is shown for the frontend identity named "public."'}),"\n",(0,o.jsxs)(n.p,{children:["Nice work! The ",(0,o.jsx)(n.code,{children:"zrok"})," controller is fully configured now that you have created the ",(0,o.jsx)(n.code,{children:"zrok"})," frontend."]}),"\n",(0,o.jsx)(n.h2,{id:"configure-the-public-frontend",children:"Configure the Public Frontend"}),"\n",(0,o.jsxs)(n.p,{children:["Create an http frontend configuration file in ",(0,o.jsx)(n.code,{children:"etc/http-frontend.yml"}),"."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-yaml",children:"v: 3\nhost_match: zrok.quigley.com\naddress: 0.0.0.0:8080\n"})}),"\n",(0,o.jsxs)(n.p,{children:["This frontend config file has a ",(0,o.jsx)(n.code,{children:"host_match"})," pattern that represents the DNS zone you're using with this instance of ",(0,o.jsx)(n.code,{children:"zrok"}),". Incoming HTTP requests with a matching ",(0,o.jsx)(n.code,{children:"Host"})," header will be handled by this frontend. You may also specify the interface address where the frontend will listen for public access requests."]}),"\n",(0,o.jsxs)(n.p,{children:["The frontend does not provide server TLS, but you may front the server with a reverse proxy. The reverse proxy must forward the ",(0,o.jsx)(n.code,{children:"Host"})," header supplied by the viewer. This example will expose the non-TLS listener for the frontend."]}),"\n",(0,o.jsxs)(n.p,{children:["You can also specify an ",(0,o.jsx)(n.code,{children:"oauth"})," configuration in this file, full details of are found in ",(0,o.jsx)(n.a,{href:"/docs/guides/self-hosting/oauth/configuring-oauth#configuring-your-public-frontend",children:"OAuth Public Frontend Configuration"}),"."]}),"\n",(0,o.jsx)(n.h2,{id:"start-public-frontend",children:"Start Public Frontend"}),"\n",(0,o.jsx)(n.p,{children:"In another terminal window, run:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok access public etc/http-frontend.yml\n[ 0.002] INFO main.(*accessPublicCommand).run: {\n\t...\n}\n[ 0.002] INFO zrok/endpoints/public_frontend.newMetricsAgent: loaded 'public' identity\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"zrok"})," frontend uses the ",(0,o.jsx)(n.code,{children:"public"})," identity created during the bootstrap process to securely access zrok backends. to provide public access for the ",(0,o.jsx)(n.code,{children:"zrok"})," deployment. It is expected that the configured listener for this frontend corresponds to the DNS template specified when creating the public frontend record above."]}),"\n",(0,o.jsx)(n.h2,{id:"create-a-user-account",children:"Create a User Account"}),"\n",(0,o.jsxs)(n.p,{children:["With our ",(0,o.jsx)(n.code,{children:"ZROK_ADMIN_TOKEN"})," and ",(0,o.jsx)(n.code,{children:"ZROK_API_ENDPOINT"})," environment variables set, we can create our first user account."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"zrok admin create account \n"})}),"\n",(0,o.jsx)(n.p,{children:"The output is the account token you will use to enable each device's zrok environment."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"SuGzRPjVDIcF\n"})}),"\n",(0,o.jsx)(n.h2,{id:"invite-additional-users",children:"Invite Additional Users"}),"\n",(0,o.jsxs)(n.p,{children:["Offer this onboarding method to your users if you have configured an email-sending service in your ",(0,o.jsx)(n.code,{children:"zrok"})," controller configuration."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"$ zrok invite\nNew Email: user@domain.com\nConfirm Email: user@domain.com\ninvitation sent to 'user@domain.com'!\n"})}),"\n",(0,o.jsxs)(n.p,{children:["If you look at the console output from your ",(0,o.jsx)(n.code,{children:"zrok"})," controller, you'll see a message like this:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"[ 238.168] INFO zrok/controller.(*inviteHandler).Handle: account request for 'user@domain.com' has registration token 'U2Ewt1UCn3ql'\n"})}),"\n",(0,o.jsxs)(n.p,{children:["You can access your ",(0,o.jsx)(n.code,{children:"zrok"})," controller's registration UI by pointing a web browser at:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"http://localhost:18080/register/U2Ewt1UCn3ql\n"})}),"\n",(0,o.jsx)(n.p,{children:"The UI will ask you to set a password for your new account. Go ahead and do that."}),"\n",(0,o.jsx)(n.p,{children:"After doing that, I see the following output in my controller console:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{children:"[ 516.778] INFO zrok/controller.(*registerHandler).Handle: created account 'user@domain.com' with token 'SuGzRPjVDIcF'\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Keep track of the token listed above (",(0,o.jsx)(n.code,{children:"SuGzRPjVDIcF"}),"). We'll use this to enable our shell for this ",(0,o.jsx)(n.code,{children:"zrok"})," deployment."]}),"\n",(0,o.jsx)(n.h2,{id:"enable-your-environment",children:"Enable Your Environment"}),"\n",(0,o.jsx)(n.p,{children:"On another device that can reach your Linux server by FQDN, configure the API endpoint and enable the environment with the account token you received when you created the first user account."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"export ZROK_API_ENDPOINT=https://zrok.quigley.com\n# or\nzrok config set apiEndpoint https://zrok.quigley.com\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"zrok enable SuGzRPjVDIcF\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"zrok environment '2AS1WZ3Sz' enabled for 'SuGzRPjVDIcF'\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"zrok status --secrets\n"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"Config:\n\n CONFIG VALUE SOURCE\n apiEndpoint https://zrok.quigley.com env\n\nEnvironment:\n\n PROPERTY VALUE\n Secret Token SuGzRPjVDIcF\n Ziti Identity 2AS1WZ3Sz\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Congratulations. You have a working ",(0,o.jsx)(n.code,{children:"zrok"})," environment!"]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(a,{...e})}):a(e)}},7996:(e,n,r)=>{r.d(n,{Z:()=>o});const o=r.p+"assets/files/ctrl-8468281a3bbdbc5852c252b0af86a113.yml"},1151:(e,n,r)=>{r.d(n,{Z:()=>l,a:()=>s});var o=r(7294);const t={},i=o.createContext(t);function s(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e1dfe4fe.309e457f.js b/assets/js/e1dfe4fe.309e457f.js deleted file mode 100644 index f82281d6..00000000 --- a/assets/js/e1dfe4fe.309e457f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4778],{3938:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>d,toc:()=>h});var r=o(5893),i=o(1151);function t(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"docker-instance",children:"Docker Instance"}),"\n",(0,r.jsx)("iframe",{width:"100%",height:"315",src:"https://www.youtube.com/embed/70zJ_h4uiD8",title:"YouTube video player",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowfullscreen:!0}),"\n",(0,r.jsx)(n.p,{children:"This Docker Compose project creates a zrok instance and includes a ziti controller and router. An optional Caddy container is included to provide HTTPS and reverse proxy services for the zrok API and public shares."}),"\n",(0,r.jsx)(n.h3,{id:"dns-configuration",children:"DNS Configuration"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["A wildcard record exists for the IP address where the zrok instance will run, e.g. if your DNS zone is ",(0,r.jsx)(n.code,{children:"share.example.com"}),", then your wildcard record is ",(0,r.jsx)(n.code,{children:"*.share.example.com"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"additional-dns-configuration-for-caddy-tls",children:"Additional DNS Configuration for Caddy TLS"}),"\n",(0,r.jsxs)(n.p,{children:["The included Caddy container can automatically manage a wildcard certificate for your zrok instance. You can enable Caddy in this compose project by renaming ",(0,r.jsx)(n.code,{children:"caddy.compose.override.yml"})," as ",(0,r.jsx)(n.code,{children:"compose.override.yml"}),"."]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Ensure A Caddy DNS plugin is available for your DNS provider (see ",(0,r.jsx)(n.a,{href:"https://github.com/orgs/caddy-dns/repositories?type=all&q=sort%3Aname-asc",children:"github.com/caddy-dns"}),")."]}),"\n",(0,r.jsxs)(n.li,{children:["Designate A DNS zone for zrok, e.g. ",(0,r.jsx)(n.code,{children:"example.com"})," or ",(0,r.jsx)(n.code,{children:"share.example.com"})," and create the zone on your DNS provider's platform."]}),"\n",(0,r.jsx)(n.li,{children:"Created an API token in your DNS provider that has permission to manage zrok's DNS zone."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"create-the-docker-compose-project",children:"Create the Docker Compose Project"}),"\n",(0,r.jsx)(n.p,{children:"Create a working directory on your Docker host and save these Docker Compose project files."}),"\n",(0,r.jsx)(n.h4,{id:"shortcut-option",children:"Shortcut Option"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Run this script to download the files in the current directory."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl https://get.openziti.io/zrok-instance/fetch.bash | bash\n"})}),"\n",(0,r.jsx)(n.p,{children:"Or, specify the Compose project directory."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl https://get.openziti.io/zrok-instance/fetch.bash | bash -s /path/to/compose/project/dir\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"manual-option",children:"Manual Option"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Get the zrok repo ZIP file."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"wget https://github.com/openziti/zrok/archive/refs/heads/main.zip\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Unzip the zrok-instance files into the project directory."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"unzip -j -d . main.zip '*/docker/compose/zrok-instance/*'\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"configure-the-docker-compose-project-environment",children:"Configure the Docker Compose Project Environment"}),"\n",(0,r.jsxs)(n.p,{children:["Create an ",(0,r.jsx)(n.code,{children:".env"})," file in the working directory."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title=".env required"',children:"ZROK_DNS_ZONE=share.example.com\n\nZROK_USER_EMAIL=me@example.com\nZROK_USER_PWD=zrokuserpw\n\nZITI_PWD=zitiadminpw\nZROK_ADMIN_TOKEN=zroktoken\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title=".env options"',children:"# Caddy TLS option: rename caddy.compose.override.yml to compose.override.yml and set these vars; allow 80,443 in firewall\n# plugin name for your DNS provider\nCADDY_DNS_PLUGIN=cloudflare\n# API token from your DNS provider\nCADDY_DNS_PLUGIN_TOKEN=abcd1234\n# use the staging API until you're sure everything is working to avoid hitting the rate limit\nCADDY_ACME_API=https://acme-staging-v02.api.letsencrypt.org/directory\n\n# no TLS option: publish the insecure ports to the internet and allow them in the firewall \nZROK_INSECURE_INTERFACE=0.0.0.0\nZROK_CTRL_PORT=18080\nZROK_FRONTEND_PORT=8080\nZROK_OAUTH_PORT=8081\n\n# ziti ports must be published to the internet and allowed by firewall\nZITI_CTRL_ADVERTISED_PORT=1280\nZITI_ROUTER_PORT=3022\n\n# configure oauth for public shares\nZROK_OAUTH_HASH_KEY=oauthhashkeysecret\nZROK_OAUTH_GITHUB_CLIENT_ID=abcd1234\nZROK_OAUTH_GITHUB_CLIENT_SECRET=abcd1234\nZROK_OAUTH_GOOGLE_CLIENT_ID=abcd1234\nZROK_OAUTH_GOOGLE_CLIENT_SECRET=abcd1234\n\n# zrok version, e.g., 1.0.0\nZROK_CLI_TAG=latest\n# ziti version, e.g., 1.0.0\nZITI_CLI_TAG=latest\n"})}),"\n",(0,r.jsx)(n.h3,{id:"start-the-docker-compose-project",children:"Start the Docker Compose Project"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Start the zrok instance."}),"\n",(0,r.jsxs)(n.p,{children:["The container images for zrok (including caddy) are built in this step. This provides a simple configuration to get started. You can modify the templates named like ",(0,r.jsx)(n.code,{children:"*.envsubst"})," or mount a customized configuration file to mask the one that was built in."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose up --build --detach\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"set-up-a-user-account",children:"Set up a User Account"}),"\n",(0,r.jsxs)(n.p,{children:["This step creates a user account. You will log in to the zrok web console with the account password created in this step. The ZROK_USER_EMAIL and ZROK_USER_PWD variables are set in the ",(0,r.jsx)(n.code,{children:".env"})," file. You can create more user accounts the same way by substituting a different email and password."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Create the first user account"',children:"docker compose exec zrok-controller bash -xc 'zrok admin create account /etc/zrok-controller/config.yml ${ZROK_USER_EMAIL} ${ZROK_USER_PWD}'\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"+ zrok admin create account /etc/zrok-controller/config.yml me@example.com zrokuserpw\n[ 0.000] INFO zrok/controller/store.Open: database connected\n[ 0.002] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\nheMqncCyxZcx\n"})}),"\n",(0,r.jsx)(n.p,{children:"Create additional users by running the command again with a different email and password."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Create another user"',children:"docker compose exec zrok-controller zrok admin create account /etc/zrok-controller/config.yml \n"})}),"\n",(0,r.jsx)(n.h3,{id:"enable-the-user-environment",children:"Enable the User Environment"}),"\n",(0,r.jsx)(n.p,{children:"You must enable each device environment with the account token obtained when the account was created. This is separate from the account password that's used to log in to the web console."}),"\n",(0,r.jsxs)(n.p,{children:["Follow ",(0,r.jsx)(n.a,{href:"/docs/getting-started#installing-the-zrok-command",children:"the getting started guide"})," to install the zrok CLI on some device and enable a zrok environment."]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["Configure the environment with the zrok API. Substitute the API endpoint with the one you're using, e.g. ",(0,r.jsx)(n.code,{children:"https://zrok.${ZROK_DNS_ZONE}"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"zrok config set apiEndpoint https://zrok.share.example.com\n"})}),"\n",(0,r.jsx)(n.p,{children:"or, if not using Caddy for TLS:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"zrok config set apiEndpoint http://zrok.share.example.com:18080\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Enable an environment on this device with the account token from the previous step."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"zrok enable heMqncCyxZcx\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"firewall-configuration",children:"Firewall Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"ziti-quickstart"})," and ",(0,r.jsx)(n.code,{children:"caddy"})," containers publish ports to all devices that use zrok shares. The ",(0,r.jsx)(n.code,{children:"zrok-controller"})," and ",(0,r.jsx)(n.code,{children:"zrok-frontend"})," containers expose ports only to the ",(0,r.jsx)(n.code,{children:"caddy"})," container and the Docker host's loopback interface."]}),"\n",(0,r.jsx)(n.h4,{id:"required",children:"Required"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"443/tcp"})," - reverse proxy handles HTTPS requests for zrok API, OAuth, and public shares (published by container ",(0,r.jsx)(n.code,{children:"caddy"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"1280/tcp"})," - ziti ctrl plane (published by container ",(0,r.jsx)(n.code,{children:"ziti-quickstart"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"3022/tcp"})," - ziti data plane (published by container ",(0,r.jsx)(n.code,{children:"ziti-quickstart"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"optional",children:"Optional"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"80/tcp"})," - reverse proxy redirects non-HTTPS requests to ",(0,r.jsx)(n.code,{children:"443/tcp"})," (published by container ",(0,r.jsx)(n.code,{children:"caddy"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Check the ziti and zrok logs."}),"\n",(0,r.jsxs)(n.p,{children:["You can substitute the service container name of each to check their logs individually: ",(0,r.jsx)(n.code,{children:"ziti-quickstart"}),", ",(0,r.jsx)(n.code,{children:"zrok-controller"}),", ",(0,r.jsx)(n.code,{children:"zrok-frontend"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose logs zrok-controller\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Check the caddy logs."}),"\n",(0,r.jsxs)(n.p,{children:["It can take a few minutes for Caddy to obtain the wildcard certificate. You can check the logs to see if there were any errors completing the DNS challenge which involves using the Caddy DNS plugin to create a TXT record in your DNS zone. This leverages the API token you provided in the ",(0,r.jsx)(n.code,{children:".env"})," file, which must have permission to create DNS records in the zrok DNS zone."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose logs caddy\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"zrok enable"})," fails certificate verification: ensure you are not using the staging API for Let's Encrypt."]}),"\n",(0,r.jsxs)(n.p,{children:["If you are using the staging API, you will see an error about the API certificate when you use the zrok CLI. You can switch to the production API by removing the overriding assignment of the ",(0,r.jsx)(n.code,{children:"CADDY_ACME_API"})," variable."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:'there was a problem enabling your environment!\nyou are trying to use the zrok service at: https://zrok.share.example.com\nyou can change your zrok service endpoint using this command:\n\n$ zrok config set apiEndpoint \n\n(where newEndpoint is something like: https://some.zrok.io)\n[ERROR]: error creating service client (error getting version from api endpoint \'https://zrok.share.example.com\': Get "https://zrok.share.example.com/api/v1/version": tls: failed to verify certificate: x509: certificate signed by unknown authority: Get "https://zrok.share.example.com/api/v1/version": tls: failed to verify certificate: x509: certificate signed by unknown authority)\n'})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Validate the Caddyfile."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Verify the correct DNS provider module was built-in to Caddy."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy caddy list-modules | grep dns.providers\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"dns.providers.cloudflare\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Verify certificates."}),"\n",(0,r.jsx)(n.p,{children:"You can check the certificates that Caddy has obtained."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy caddy list-certificates\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Use the Caddy admin API."}),"\n",(0,r.jsxs)(n.p,{children:["You can use the Caddy admin API to check the status of the Caddy instance. The admin API is available on port ",(0,r.jsx)(n.code,{children:"2019/tcp"})," inside the Docker Compose project. You can modify ",(0,r.jsx)(n.code,{children:"compose.override.yml"})," to publish the port if you want to access the admin API from the Docker host or elsewhere."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy curl http://localhost:2019/config/ | jq\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"My provider, e.g., Route53 doesn't give me a single API token."}),"\n",(0,r.jsxs)(n.p,{children:["As long as your DNS provider is supported by Caddy then it will work. You can modify the Caddyfile to use a different set of properties than the example. Here's how the ",(0,r.jsx)(n.code,{children:"tls"})," section should look for Route53."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:"tls {\n dns {$CADDY_DNS_PLUGIN} {\n access_key_id {$AWS_ACCESS_KEY_ID}\n secret_access_key {$AWS_SECRET_ACCESS_KEY}\n }\n}\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title=".env"',children:"CADDY_DNS_PLUGIN=route53\nAWS_ACCESS_KEY_ID=abcd1234\nAWS_SECRET_ACCESS_KEY=abcd1234\n"})}),"\n"]}),"\n"]})]})}function s(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(t,{...e})}):t(e)}const c={title:"Self-hosting guide for Docker",sidebar_label:"Docker",sidebar_position:45},a=void 0,d={id:"guides/self-hosting/docker",title:"Self-hosting guide for Docker",description:"",source:"@site/../docs/guides/self-hosting/docker.mdx",sourceDirName:"guides/self-hosting",slug:"/guides/self-hosting/docker",permalink:"/docs/guides/self-hosting/docker",draft:!1,unlisted:!1,editUrl:"https://github.com/openziti/zrok/blob/main/docs/../docs/guides/self-hosting/docker.mdx",tags:[],version:"current",sidebarPosition:45,frontMatter:{title:"Self-hosting guide for Docker",sidebar_label:"Docker",sidebar_position:45},sidebar:"tutorialSidebar",previous:{title:"Personalized Frontend",permalink:"/docs/guides/self-hosting/personalized-frontend"},next:{title:"Metrics and Limits",permalink:"/docs/category/metrics-and-limits"}},l={},h=[{value:"Docker Instance",id:"docker-instance",level:2},{value:"DNS Configuration",id:"dns-configuration",level:3},{value:"Additional DNS Configuration for Caddy TLS",id:"additional-dns-configuration-for-caddy-tls",level:4},{value:"Create the Docker Compose Project",id:"create-the-docker-compose-project",level:3},{value:"Shortcut Option",id:"shortcut-option",level:4},{value:"Manual Option",id:"manual-option",level:4},{value:"Configure the Docker Compose Project Environment",id:"configure-the-docker-compose-project-environment",level:3},{value:"Start the Docker Compose Project",id:"start-the-docker-compose-project",level:3},{value:"Set up a User Account",id:"set-up-a-user-account",level:3},{value:"Enable the User Environment",id:"enable-the-user-environment",level:3},{value:"Firewall Configuration",id:"firewall-configuration",level:3},{value:"Required",id:"required",level:4},{value:"Optional",id:"optional",level:4},{value:"Troubleshooting",id:"troubleshooting",level:3}];function p(e){return(0,r.jsx)(s,{})}function u(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(p,{...e})}):p()}},1151:(e,n,o)=>{o.d(n,{Z:()=>c,a:()=>s});var r=o(7294);const i={},t=r.createContext(i);function s(e){const n=r.useContext(t);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e1dfe4fe.44c158fb.js b/assets/js/e1dfe4fe.44c158fb.js new file mode 100644 index 00000000..c51f3934 --- /dev/null +++ b/assets/js/e1dfe4fe.44c158fb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[4778],{3938:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>c,metadata:()=>d,toc:()=>h});var r=o(5893),i=o(1151);function t(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"docker-instance",children:"Docker Instance"}),"\n",(0,r.jsx)("iframe",{width:"100%",height:"315",src:"https://www.youtube.com/embed/70zJ_h4uiD8",title:"YouTube video player",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",allowfullscreen:!0}),"\n",(0,r.jsx)(n.p,{children:"This Docker Compose project creates a zrok instance and includes a ziti controller and router. An optional Caddy container is included to provide HTTPS and reverse proxy services for the zrok API and public shares."}),"\n",(0,r.jsx)(n.h3,{id:"dns-configuration",children:"DNS Configuration"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["A wildcard record exists for the IP address where the zrok instance will run, e.g. if your DNS zone is ",(0,r.jsx)(n.code,{children:"share.example.com"}),", then your wildcard record is ",(0,r.jsx)(n.code,{children:"*.share.example.com"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"additional-dns-configuration-for-caddy-tls",children:"Additional DNS Configuration for Caddy TLS"}),"\n",(0,r.jsxs)(n.p,{children:["The included Caddy container can automatically manage a wildcard certificate for your zrok instance. You can enable Caddy in this compose project by renaming ",(0,r.jsx)(n.code,{children:"compose.caddy.yml"})," as ",(0,r.jsx)(n.code,{children:"compose.override.yml"}),"."]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Ensure A Caddy DNS plugin is available for your DNS provider (see ",(0,r.jsx)(n.a,{href:"https://github.com/orgs/caddy-dns/repositories?type=all&q=sort%3Aname-asc",children:"github.com/caddy-dns"}),")."]}),"\n",(0,r.jsxs)(n.li,{children:["Designate A DNS zone for zrok, e.g. ",(0,r.jsx)(n.code,{children:"example.com"})," or ",(0,r.jsx)(n.code,{children:"share.example.com"})," and create the zone on your DNS provider's platform."]}),"\n",(0,r.jsx)(n.li,{children:"Created an API token in your DNS provider that has permission to manage zrok's DNS zone."}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"create-the-docker-compose-project",children:"Create the Docker Compose Project"}),"\n",(0,r.jsx)(n.p,{children:"Create a working directory on your Docker host and save these Docker Compose project files."}),"\n",(0,r.jsx)(n.h4,{id:"shortcut-option",children:"Shortcut Option"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Run this script to download the files in the current directory."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl https://get.openziti.io/zrok-instance/fetch.bash | bash\n"})}),"\n",(0,r.jsx)(n.p,{children:"Or, specify the Compose project directory."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl https://get.openziti.io/zrok-instance/fetch.bash | bash -s /path/to/compose/project/dir\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"manual-option",children:"Manual Option"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Get the zrok repo ZIP file."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"wget https://github.com/openziti/zrok/archive/refs/heads/main.zip\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Unzip the zrok-instance files into the project directory."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"unzip -j -d . main.zip '*/docker/compose/zrok-instance/*'\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"configure-the-docker-compose-project-environment",children:"Configure the Docker Compose Project Environment"}),"\n",(0,r.jsxs)(n.p,{children:["Create an ",(0,r.jsx)(n.code,{children:".env"})," file in the working directory."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title=".env required"',children:"ZROK_DNS_ZONE=share.example.com\n\nZROK_USER_EMAIL=me@example.com\nZROK_USER_PWD=zrokuserpw\n\nZITI_PWD=zitiadminpw\nZROK_ADMIN_TOKEN=zroktoken\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title=".env options"',children:"# Caddy TLS option: rename compose.caddy.yml to compose.override.yml and set these vars; allow 80,443 in firewall\n# plugin name for your DNS provider\nCADDY_DNS_PLUGIN=cloudflare\n# API token from your DNS provider\nCADDY_DNS_PLUGIN_TOKEN=abcd1234\n# use the staging API until you're sure everything is working to avoid hitting the rate limit\nCADDY_ACME_API=https://acme-staging-v02.api.letsencrypt.org/directory\n\n# no TLS option: publish the insecure ports to the internet and allow them in the firewall \nZROK_INSECURE_INTERFACE=0.0.0.0\nZROK_CTRL_PORT=18080\nZROK_FRONTEND_PORT=8080\nZROK_OAUTH_PORT=8081\n\n# ziti ports must be published to the internet and allowed by firewall\nZITI_CTRL_ADVERTISED_PORT=1280\nZITI_ROUTER_PORT=3022\n\n# configure oauth for public shares\nZROK_OAUTH_HASH_KEY=oauthhashkeysecret\nZROK_OAUTH_GITHUB_CLIENT_ID=abcd1234\nZROK_OAUTH_GITHUB_CLIENT_SECRET=abcd1234\nZROK_OAUTH_GOOGLE_CLIENT_ID=abcd1234\nZROK_OAUTH_GOOGLE_CLIENT_SECRET=abcd1234\n\n# zrok version, e.g., 1.0.0\nZROK_CLI_TAG=latest\n# ziti version, e.g., 1.0.0\nZITI_CLI_TAG=latest\n"})}),"\n",(0,r.jsx)(n.h3,{id:"start-the-docker-compose-project",children:"Start the Docker Compose Project"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Start the zrok instance."}),"\n",(0,r.jsxs)(n.p,{children:["The container images for zrok (including caddy) are built in this step. This provides a simple configuration to get started. You can modify the templates named like ",(0,r.jsx)(n.code,{children:"*.envsubst"})," or mount a customized configuration file to mask the one that was built in."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose up --build --detach\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"set-up-a-user-account",children:"Set up a User Account"}),"\n",(0,r.jsxs)(n.p,{children:["This step creates a user account. You will log in to the zrok web console with the account password created in this step. The ZROK_USER_EMAIL and ZROK_USER_PWD variables are set in the ",(0,r.jsx)(n.code,{children:".env"})," file. You can create more user accounts the same way by substituting a different email and password."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Create the first user account"',children:"docker compose exec zrok-controller bash -xc 'zrok admin create account ${ZROK_USER_EMAIL} ${ZROK_USER_PWD}'\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"+ zrok admin create account me@example.com zrokuserpw\n[ 0.000] INFO zrok/controller/store.Open: database connected\n[ 0.002] INFO zrok/controller/store.(*Store).migrate: applied 0 migrations\nheMqncCyxZcx\n"})}),"\n",(0,r.jsx)(n.p,{children:"Create additional users by running the command again with a different email and password."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title="Create another user"',children:"docker compose exec zrok-controller zrok admin create account \n"})}),"\n",(0,r.jsx)(n.h3,{id:"enable-the-user-environment",children:"Enable the User Environment"}),"\n",(0,r.jsx)(n.p,{children:"You must enable each device environment with the account token obtained when the account was created. This is separate from the account password that's used to log in to the web console."}),"\n",(0,r.jsxs)(n.p,{children:["Follow ",(0,r.jsx)(n.a,{href:"/docs/getting-started#installing-the-zrok-command",children:"the getting started guide"})," to install the zrok CLI on some device and enable a zrok environment."]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["Configure the environment with the zrok API. Substitute the API endpoint with the one you're using, e.g. ",(0,r.jsx)(n.code,{children:"https://zrok.${ZROK_DNS_ZONE}"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"zrok config set apiEndpoint https://zrok.share.example.com\n"})}),"\n",(0,r.jsx)(n.p,{children:"or, if not using Caddy for TLS:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"zrok config set apiEndpoint http://zrok.share.example.com:18080\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Enable an environment on this device with the account token from the previous step."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"zrok enable heMqncCyxZcx\n"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"firewall-configuration",children:"Firewall Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"ziti-quickstart"})," and ",(0,r.jsx)(n.code,{children:"caddy"})," containers publish ports to all devices that use zrok shares. The ",(0,r.jsx)(n.code,{children:"zrok-controller"})," and ",(0,r.jsx)(n.code,{children:"zrok-frontend"})," containers expose ports only to the ",(0,r.jsx)(n.code,{children:"caddy"})," container and the Docker host's loopback interface."]}),"\n",(0,r.jsx)(n.h4,{id:"required",children:"Required"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"443/tcp"})," - reverse proxy handles HTTPS requests for zrok API, OAuth, and public shares (published by container ",(0,r.jsx)(n.code,{children:"caddy"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"1280/tcp"})," - ziti ctrl plane (published by container ",(0,r.jsx)(n.code,{children:"ziti-quickstart"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"3022/tcp"})," - ziti data plane (published by container ",(0,r.jsx)(n.code,{children:"ziti-quickstart"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h4,{id:"optional",children:"Optional"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"80/tcp"})," - reverse proxy redirects non-HTTPS requests to ",(0,r.jsx)(n.code,{children:"443/tcp"})," (published by container ",(0,r.jsx)(n.code,{children:"caddy"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Check the ziti and zrok logs."}),"\n",(0,r.jsxs)(n.p,{children:["You can substitute the service container name of each to check their logs individually: ",(0,r.jsx)(n.code,{children:"ziti-quickstart"}),", ",(0,r.jsx)(n.code,{children:"zrok-controller"}),", ",(0,r.jsx)(n.code,{children:"zrok-frontend"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose logs zrok-controller\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Check the caddy logs."}),"\n",(0,r.jsxs)(n.p,{children:["It can take a few minutes for Caddy to obtain the wildcard certificate. You can check the logs to see if there were any errors completing the DNS challenge which involves using the Caddy DNS plugin to create a TXT record in your DNS zone. This leverages the API token you provided in the ",(0,r.jsx)(n.code,{children:".env"})," file, which must have permission to create DNS records in the zrok DNS zone."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose logs caddy\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"zrok enable"})," fails certificate verification: ensure you are not using the staging API for Let's Encrypt."]}),"\n",(0,r.jsxs)(n.p,{children:["If you are using the staging API, you will see an error about the API certificate when you use the zrok CLI. You can switch to the production API by removing the overriding assignment of the ",(0,r.jsx)(n.code,{children:"CADDY_ACME_API"})," variable."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:'there was a problem enabling your environment!\nyou are trying to use the zrok service at: https://zrok.share.example.com\nyou can change your zrok service endpoint using this command:\n\n$ zrok config set apiEndpoint \n\n(where newEndpoint is something like: https://some.zrok.io)\n[ERROR]: error creating service client (error getting version from api endpoint \'https://zrok.share.example.com\': Get "https://zrok.share.example.com/api/v1/version": tls: failed to verify certificate: x509: certificate signed by unknown authority: Get "https://zrok.share.example.com/api/v1/version": tls: failed to verify certificate: x509: certificate signed by unknown authority)\n'})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Validate the Caddyfile."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Verify the correct DNS provider module was built-in to Caddy."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy caddy list-modules | grep dns.providers\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-buttonless",metastring:'title="Example output"',children:"dns.providers.cloudflare\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Verify certificates."}),"\n",(0,r.jsx)(n.p,{children:"You can check the certificates that Caddy has obtained."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy caddy list-certificates\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Use the Caddy admin API."}),"\n",(0,r.jsxs)(n.p,{children:["You can use the Caddy admin API to check the status of the Caddy instance. The admin API is available on port ",(0,r.jsx)(n.code,{children:"2019/tcp"})," inside the Docker Compose project. You can modify ",(0,r.jsx)(n.code,{children:"compose.override.yml"})," to publish the port if you want to access the admin API from the Docker host or elsewhere."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker compose exec caddy curl http://localhost:2019/config/ | jq\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"My provider, e.g., Route53 doesn't give me a single API token."}),"\n",(0,r.jsxs)(n.p,{children:["As long as your DNS provider is supported by Caddy then it will work. You can modify the Caddyfile to use a different set of properties than the example. Here's how the ",(0,r.jsx)(n.code,{children:"tls"})," section should look for Route53."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:"tls {\n dns {$CADDY_DNS_PLUGIN} {\n access_key_id {$AWS_ACCESS_KEY_ID}\n secret_access_key {$AWS_SECRET_ACCESS_KEY}\n }\n}\n"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",metastring:'title=".env"',children:"CADDY_DNS_PLUGIN=route53\nAWS_ACCESS_KEY_ID=abcd1234\nAWS_SECRET_ACCESS_KEY=abcd1234\n"})}),"\n"]}),"\n"]})]})}function s(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(t,{...e})}):t(e)}const c={title:"Self-hosting guide for Docker",sidebar_label:"Docker",sidebar_position:45},a=void 0,d={id:"guides/self-hosting/docker",title:"Self-hosting guide for Docker",description:"",source:"@site/../docs/guides/self-hosting/docker.mdx",sourceDirName:"guides/self-hosting",slug:"/guides/self-hosting/docker",permalink:"/docs/guides/self-hosting/docker",draft:!1,unlisted:!1,editUrl:"https://github.com/openziti/zrok/blob/main/docs/../docs/guides/self-hosting/docker.mdx",tags:[],version:"current",sidebarPosition:45,frontMatter:{title:"Self-hosting guide for Docker",sidebar_label:"Docker",sidebar_position:45},sidebar:"tutorialSidebar",previous:{title:"Personalized Frontend",permalink:"/docs/guides/self-hosting/personalized-frontend"},next:{title:"Metrics and Limits",permalink:"/docs/category/metrics-and-limits"}},l={},h=[{value:"Docker Instance",id:"docker-instance",level:2},{value:"DNS Configuration",id:"dns-configuration",level:3},{value:"Additional DNS Configuration for Caddy TLS",id:"additional-dns-configuration-for-caddy-tls",level:4},{value:"Create the Docker Compose Project",id:"create-the-docker-compose-project",level:3},{value:"Shortcut Option",id:"shortcut-option",level:4},{value:"Manual Option",id:"manual-option",level:4},{value:"Configure the Docker Compose Project Environment",id:"configure-the-docker-compose-project-environment",level:3},{value:"Start the Docker Compose Project",id:"start-the-docker-compose-project",level:3},{value:"Set up a User Account",id:"set-up-a-user-account",level:3},{value:"Enable the User Environment",id:"enable-the-user-environment",level:3},{value:"Firewall Configuration",id:"firewall-configuration",level:3},{value:"Required",id:"required",level:4},{value:"Optional",id:"optional",level:4},{value:"Troubleshooting",id:"troubleshooting",level:3}];function p(e){return(0,r.jsx)(s,{})}function u(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(p,{...e})}):p()}},1151:(e,n,o)=>{o.d(n,{Z:()=>c,a:()=>s});var r=o(7294);const i={},t=r.createContext(i);function s(e){const n=r.useContext(t);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.ad0ba528.js b/assets/js/runtime~main.9efafe91.js similarity index 97% rename from assets/js/runtime~main.ad0ba528.js rename to assets/js/runtime~main.9efafe91.js index 1f3592f2..110506e6 100644 --- a/assets/js/runtime~main.ad0ba528.js +++ b/assets/js/runtime~main.9efafe91.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,t,r,b,d={},c={};function f(e){var a=c[e];if(void 0!==a)return a.exports;var t=c[e]={id:e,loaded:!1,exports:{}};return d[e].call(t.exports,t,t.exports,f),t.loaded=!0,t.exports}f.m=d,f.c=c,f.amdO={},e=[],f.O=(a,t,r,b)=>{if(!t){var d=1/0;for(i=0;i=b)&&Object.keys(f.O).every((e=>f.O[e](t[o])))?t.splice(o--,1):(c=!1,b0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[t,r,b]},f.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return f.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var b=Object.create(null);f.r(b);var d={};a=a||[null,t({}),t([]),t(t)];for(var c=2&r&&e;"object"==typeof c&&!~a.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((a=>d[a]=()=>e[a]));return d.default=()=>e,f.d(b,d),b},f.d=(e,a)=>{for(var t in a)f.o(a,t)&&!f.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((a,t)=>(f.f[t](e,a),a)),[])),f.u=e=>"assets/js/"+({58:"0c66edb9",826:"47881d5c",960:"b186d866",1004:"c141421f",1360:"34e1d3b9",1387:"4555b262",1889:"339d500a",2108:"288b1075",2732:"c015c796",2914:"618abc13",2992:"f2348458",3182:"6e881e32",3629:"aba21aa0",4031:"ef8afbfd",4195:"c4f5d8e4",4196:"bbbe662c",4368:"a94703ab",4778:"e1dfe4fe",4838:"75b20590",4900:"600b2345",4920:"7452427d",5327:"c304be44",5882:"d768dc0f",5889:"cda0d2e5",5893:"2da89d45",5980:"a7456010",6062:"88b6e020",6913:"b6569025",7076:"2e812224",7142:"1ba5bc99",7176:"6272ba0e",7273:"9939c4f4",7918:"17896441",7920:"1a4e3797",8156:"21880a4d",8198:"50ef9c44",8518:"a7bd4aaa",8905:"07d0b302",8938:"f888b719",8945:"bc747cac",8993:"5cd0a723",9661:"5e95c892",9714:"d9f29b48",9817:"14eb3368",9944:"ea84f538"}[e]||e)+"."+{58:"025d65ff",174:"691dcdd4",826:"6ad35172",960:"64871ffa",1004:"3e38baa4",1272:"43cc57fb",1360:"01c3d2bc",1387:"9af6f458",1426:"726339ca",1772:"2df7b54f",1889:"039a1491",2108:"a9435f23",2312:"2f123ece",2732:"c04c1507",2914:"60953b95",2992:"19be6454",3182:"e03d93bb",3629:"b0420849",4031:"0ccb2eb2",4195:"ef51316b",4196:"48b3d7ab",4368:"21ee911e",4778:"309e457f",4838:"3455a494",4900:"f8dd2591",4920:"29fd1dda",5327:"4a777c27",5882:"8e1de618",5889:"236e5d28",5893:"49a97a4b",5980:"37bc4934",6062:"fa69d636",6913:"e0ac939e",6945:"8e8e2060",7076:"5284992e",7142:"37030d6d",7176:"35172d6c",7273:"75a5b179",7918:"48128ac6",7920:"56015c27",8156:"ffe0573f",8198:"5df32fc9",8518:"45274bc2",8894:"46125374",8905:"2f581655",8938:"b3481d16",8945:"975267a6",8993:"e3585e3a",9661:"d1615a49",9714:"6d24467b",9817:"038d23ea",9944:"d5db2b03"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},b="website:",f.l=(e,a,t,d)=>{if(r[e])r[e].push(a);else{var c,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var b=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),b&&b.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=l.bind(null,c.onerror),c.onload=l.bind(null,c.onload),o&&document.head.appendChild(c)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/",f.gca=function(e){return e={17896441:"7918","0c66edb9":"58","47881d5c":"826",b186d866:"960",c141421f:"1004","34e1d3b9":"1360","4555b262":"1387","339d500a":"1889","288b1075":"2108",c015c796:"2732","618abc13":"2914",f2348458:"2992","6e881e32":"3182",aba21aa0:"3629",ef8afbfd:"4031",c4f5d8e4:"4195",bbbe662c:"4196",a94703ab:"4368",e1dfe4fe:"4778","75b20590":"4838","600b2345":"4900","7452427d":"4920",c304be44:"5327",d768dc0f:"5882",cda0d2e5:"5889","2da89d45":"5893",a7456010:"5980","88b6e020":"6062",b6569025:"6913","2e812224":"7076","1ba5bc99":"7142","6272ba0e":"7176","9939c4f4":"7273","1a4e3797":"7920","21880a4d":"8156","50ef9c44":"8198",a7bd4aaa:"8518","07d0b302":"8905",f888b719:"8938",bc747cac:"8945","5cd0a723":"8993","5e95c892":"9661",d9f29b48:"9714","14eb3368":"9817",ea84f538:"9944"}[e]||e,f.p+f.u(e)},(()=>{var e={1303:0,532:0};f.f.j=(a,t)=>{var r=f.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var b=new Promise(((t,b)=>r=e[a]=[t,b]));t.push(r[2]=b);var d=f.p+f.u(a),c=new Error;f.l(d,(t=>{if(f.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var b=t&&("load"===t.type?"missing":t.type),d=t&&t.target&&t.target.src;c.message="Loading chunk "+a+" failed.\n("+b+": "+d+")",c.name="ChunkLoadError",c.type=b,c.request=d,r[1](c)}}),"chunk-"+a,a)}},f.O.j=a=>0===e[a];var a=(a,t)=>{var r,b,d=t[0],c=t[1],o=t[2],n=0;if(d.some((a=>0!==e[a]))){for(r in c)f.o(c,r)&&(f.m[r]=c[r]);if(o)var i=o(f)}for(a&&a(t);n{"use strict";var e,a,t,r,b,d={},c={};function f(e){var a=c[e];if(void 0!==a)return a.exports;var t=c[e]={id:e,loaded:!1,exports:{}};return d[e].call(t.exports,t,t.exports,f),t.loaded=!0,t.exports}f.m=d,f.c=c,f.amdO={},e=[],f.O=(a,t,r,b)=>{if(!t){var d=1/0;for(i=0;i=b)&&Object.keys(f.O).every((e=>f.O[e](t[o])))?t.splice(o--,1):(c=!1,b0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[t,r,b]},f.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return f.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var b=Object.create(null);f.r(b);var d={};a=a||[null,t({}),t([]),t(t)];for(var c=2&r&&e;"object"==typeof c&&!~a.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((a=>d[a]=()=>e[a]));return d.default=()=>e,f.d(b,d),b},f.d=(e,a)=>{for(var t in a)f.o(a,t)&&!f.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((a,t)=>(f.f[t](e,a),a)),[])),f.u=e=>"assets/js/"+({58:"0c66edb9",826:"47881d5c",960:"b186d866",1004:"c141421f",1360:"34e1d3b9",1387:"4555b262",1889:"339d500a",2108:"288b1075",2732:"c015c796",2914:"618abc13",2992:"f2348458",3182:"6e881e32",3629:"aba21aa0",4031:"ef8afbfd",4195:"c4f5d8e4",4196:"bbbe662c",4368:"a94703ab",4778:"e1dfe4fe",4838:"75b20590",4900:"600b2345",4920:"7452427d",5327:"c304be44",5882:"d768dc0f",5889:"cda0d2e5",5893:"2da89d45",5980:"a7456010",6062:"88b6e020",6913:"b6569025",7076:"2e812224",7142:"1ba5bc99",7176:"6272ba0e",7273:"9939c4f4",7918:"17896441",7920:"1a4e3797",8156:"21880a4d",8198:"50ef9c44",8518:"a7bd4aaa",8905:"07d0b302",8938:"f888b719",8945:"bc747cac",8993:"5cd0a723",9661:"5e95c892",9714:"d9f29b48",9817:"14eb3368",9944:"ea84f538"}[e]||e)+"."+{58:"025d65ff",174:"691dcdd4",826:"6ad35172",960:"64871ffa",1004:"3e38baa4",1272:"43cc57fb",1360:"01c3d2bc",1387:"9af6f458",1426:"726339ca",1772:"2df7b54f",1889:"039a1491",2108:"a9435f23",2312:"2f123ece",2732:"c04c1507",2914:"60953b95",2992:"19be6454",3182:"e03d93bb",3629:"b0420849",4031:"0ccb2eb2",4195:"ef51316b",4196:"48b3d7ab",4368:"21ee911e",4778:"44c158fb",4838:"3455a494",4900:"f8dd2591",4920:"29fd1dda",5327:"4a777c27",5882:"374d3e8d",5889:"236e5d28",5893:"49a97a4b",5980:"37bc4934",6062:"fa69d636",6913:"e0ac939e",6945:"8e8e2060",7076:"5284992e",7142:"37030d6d",7176:"35172d6c",7273:"75a5b179",7918:"48128ac6",7920:"56015c27",8156:"ffe0573f",8198:"5df32fc9",8518:"45274bc2",8894:"46125374",8905:"2f581655",8938:"b3481d16",8945:"975267a6",8993:"e3585e3a",9661:"d1615a49",9714:"6d24467b",9817:"038d23ea",9944:"d5db2b03"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},b="website:",f.l=(e,a,t,d)=>{if(r[e])r[e].push(a);else{var c,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var b=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),b&&b.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=l.bind(null,c.onerror),c.onload=l.bind(null,c.onload),o&&document.head.appendChild(c)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/",f.gca=function(e){return e={17896441:"7918","0c66edb9":"58","47881d5c":"826",b186d866:"960",c141421f:"1004","34e1d3b9":"1360","4555b262":"1387","339d500a":"1889","288b1075":"2108",c015c796:"2732","618abc13":"2914",f2348458:"2992","6e881e32":"3182",aba21aa0:"3629",ef8afbfd:"4031",c4f5d8e4:"4195",bbbe662c:"4196",a94703ab:"4368",e1dfe4fe:"4778","75b20590":"4838","600b2345":"4900","7452427d":"4920",c304be44:"5327",d768dc0f:"5882",cda0d2e5:"5889","2da89d45":"5893",a7456010:"5980","88b6e020":"6062",b6569025:"6913","2e812224":"7076","1ba5bc99":"7142","6272ba0e":"7176","9939c4f4":"7273","1a4e3797":"7920","21880a4d":"8156","50ef9c44":"8198",a7bd4aaa:"8518","07d0b302":"8905",f888b719:"8938",bc747cac:"8945","5cd0a723":"8993","5e95c892":"9661",d9f29b48:"9714","14eb3368":"9817",ea84f538:"9944"}[e]||e,f.p+f.u(e)},(()=>{var e={1303:0,532:0};f.f.j=(a,t)=>{var r=f.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var b=new Promise(((t,b)=>r=e[a]=[t,b]));t.push(r[2]=b);var d=f.p+f.u(a),c=new Error;f.l(d,(t=>{if(f.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var b=t&&("load"===t.type?"missing":t.type),d=t&&t.target&&t.target.src;c.message="Loading chunk "+a+" failed.\n("+b+": "+d+")",c.name="ChunkLoadError",c.type=b,c.request=d,r[1](c)}}),"chunk-"+a,a)}},f.O.j=a=>0===e[a];var a=(a,t)=>{var r,b,d=t[0],c=t[1],o=t[2],n=0;if(d.some((a=>0!==e[a]))){for(r in c)f.o(c,r)&&(f.m[r]=c[r]);if(o)var i=o(f)}for(a&&a(t);n