# Kimsufi or VPS development server: Cloudflare Tunnel and Access kit Prepared October 29, 2026. [Read the accompanying article](https://jwatte.com/blog/kimsufi-vps-cloudflare-tunnel-access/). This kit puts a staging application and a small internal wiki behind an email login. It assumes a fresh Ubuntu 24.04 LTS server, one person comfortable with Linux, and an existing domain. Use example data until backups, recovery and access tests pass. The commands are instructions for your new server; this article's research did not provision a server or connect a live tunnel. ## One page plan 1. Pick a server you can afford to rebuild. A small VPS is enough for an initial trial; a Kimsufi dedicated server is useful when its actual hardware and available stock suit the work. 2. Name an owner and a backup administrator. Record the provider's recovery procedure before changing SSH or firewall settings. 3. Install Ubuntu LTS, add an administrator with SSH keys, update it and restrict incoming traffic. 4. Run applications on loopback addresses, with separate application accounts and no public database ports. 5. Create an Access application for each hostname and allow named email addresses. Add One-time PIN explicitly. 6. Install `cloudflared` from Cloudflare's package repository. Choose the dashboard method or the configuration file method below, not both for the same tunnel. 7. Add routes, validate Access tokens at the connector, and test allowed and denied users. Only then remove remaining public SSH access if using the SSH tunnel option. 8. Back up application data off the server, restore a sample and record the result. Review updates, logs, access and bills every month. Our initial planning range is 4 to 12 setup hours and 1 to 3 administration hours each month for one server. This excludes building the application and dealing with a serious incident. ## Prerequisites - [ ] A Cloudflare account with strong account security and a second recovery method. - [ ] An active domain using Cloudflare DNS. This kit uses the normal full DNS setup. Preserve existing email records when moving nameservers. - [ ] A Cloudflare Zero Trust organization. The Free plan allows up to 50 users; the published paid price is $7 per user per month. These are separate from website CDN plan prices. - [ ] A newly provisioned Ubuntu 24.04 LTS server, its initial SSH details and a working provider console or rescue procedure. - [ ] An SSH client on your computer and an SSH key protected with a passphrase. - [ ] An application already configured to listen only on `localhost:8080`, plus an optional second application on `localhost:8081`. - [ ] The real email addresses of each person allowed into each application. - [ ] An off site backup destination, encryption credentials stored separately, and enough retained storage for all versions. Examples use `staging.example.com`, `wiki.example.com` and `ssh.example.com`. Replace these with your own hostnames. Replace every value written as `` before running a command. Angle brackets are placeholders, not literal shell input. Never paste tunnel tokens, service token secrets, private SSH keys or tunnel credential files into a repository or support ticket. Sources: [Cloudflare application prerequisites](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/), [Zero Trust plans](https://www.cloudflare.com/plans/zero-trust-services/), read October 29, 2026. ## 1. Establish SSH and a named administrator Keep the original provider session open throughout this step. If the image already has a named sudo user, use that account. Otherwise connect with the provider's initial account and create `devadmin`. Here `devadmin` is a sample Linux username. On your computer, generate a key if you do not already have one, and make the initial connection. Verify the server host key using the provider console before accepting it. Source: [Ubuntu OpenSSH](https://documentation.ubuntu.com/server/how-to/security/openssh-server/), read October 29, 2026. ```sh ssh-keygen -t ed25519 ssh '@' ``` On the server, create the account and grant sudo access. If the initial account is root, omit `sudo`. Source: [Ubuntu user management](https://documentation.ubuntu.com/server/how-to/security/user-management/), read October 29, 2026. ```sh sudo adduser devadmin sudo adduser devadmin sudo ``` From your computer, copy the public key and open a second session. `ssh-copy-id` requires an already working authentication method; if the provider disables password login, use the still open privileged SSH session and the fallback below instead. Do not enable password login just to make this command work. Source: [Ubuntu OpenSSH](https://documentation.ubuntu.com/server/how-to/security/openssh-server/). ```sh ssh-copy-id 'devadmin@' ssh 'devadmin@' sudo -v ``` If the new account cannot accept `ssh-copy-id`, return to the original privileged server session. Switch to the new account, create its SSH directory and append your public key. The sample key line is a placeholder: paste the complete public key from your computer, never its private key. Run this only for the new account. Source: [Ubuntu SSH authorized keys](https://documentation.ubuntu.com/server/how-to/security/openssh-server/). ```sh sudo -iu devadmin mkdir -p ~/.ssh chmod 700 ~/.ssh cat >> ~/.ssh/authorized_keys <<'PUBLIC_KEY' PUBLIC_KEY chmod 600 ~/.ssh/authorized_keys exit ``` Then repeat the SSH connection from your computer and verify sudo. This fallback uses your original working session and does not require a graphical provider console. Confirm that the second session uses your SSH key and that sudo works. Then use the OpenSSH configuration instructions to disable password authentication and direct root login. Ubuntu reads configuration snippets from `/etc/ssh/sshd_config.d/`; existing provider snippets can take precedence. Save the following in `/etc/ssh/sshd_config.d/00-dev-access.conf` with your administrator editor. Verify the effective configuration rather than assuming the last file wins. The intended settings are: ```text PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin no ``` Validate before restarting. Reconnect again before closing the first session. Source: [Ubuntu OpenSSH configuration and validation](https://documentation.ubuntu.com/server/how-to/security/openssh-server/). ```sh sudo sshd -t sudo sshd -T sudo systemctl restart ssh.service ``` ## 2. Update Ubuntu and enable automatic security updates Run on the server. Review any proposed package removals or service restarts. Sources: [Ubuntu package management](https://documentation.ubuntu.com/server/how-to/software/package-management/) and [automatic updates](https://documentation.ubuntu.com/server/how-to/software/automatic-updates/), read October 29, 2026. ```sh sudo apt update sudo apt upgrade sudo apt install unattended-upgrades ufw curl ``` Check `/etc/apt/apt.conf.d/20auto-upgrades` and ensure these values are present. Edit the file with your normal administrator editor; preserve any other settings you need. Source: [Ubuntu automatic updates](https://documentation.ubuntu.com/server/how-to/software/automatic-updates/). ```text APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; ``` Review `/etc/apt/apt.conf.d/50unattended-upgrades` and its allowed origins. Ubuntu's security updates do not automatically mean every third party repository is covered. Schedule reboots and check update failures. Update `cloudflared` separately using step 11. ## 3. Set the firewall without losing the recovery path Use your computer's current public IP address, not the server's address, in the allow rule. If your connection changes address regularly, arrange reliable recovery before narrowing SSH access. This kit leaves outbound connections allowed so package updates, DNS and the tunnel can work. Sources: [Ubuntu firewall guide](https://documentation.ubuntu.com/server/how-to/security/firewalls/), [Ubuntu ufw manual](https://manpages.ubuntu.com/manpages/noble/en/man8/ufw.8.html), read October 29, 2026. ```sh sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow from '' to any port 22 proto tcp sudo ufw enable sudo ufw status numbered ``` Test a new SSH connection immediately. Do not open ports 80, 443, 8080 or 8081 for the applications. Repeat the restriction at the provider firewall if one is available. Review IPv6 too. If containers or other software add their own networking rules, verify externally that the application cannot be reached directly; do not assume the ufw display covers every published container port. Cloudflare Tunnel requires outbound port 7844 for its connections, using UDP for QUIC or TCP for HTTP/2. A restrictive egress policy needs Cloudflare's documented destinations and the supporting DNS and update traffic. Source: [Tunnel firewall requirements](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/tunnel-with-firewall/), read October 29, 2026. ## 4. Create the email login before publishing a hostname The following names match Cloudflare's documentation read October 29, 2026. Dashboard layouts can change. 1. Open **Zero Trust > Integrations > Identity providers**. 2. Under **Your identity providers**, select **Add new identity provider**, then **One-time PIN**. New organizations no longer receive OTP automatically. 3. Open **Zero Trust > Access controls > Policies** and select **Add a policy**. 4. Name it for one application, such as `Staging reviewers`. Set **Action** to **Allow**. 5. Set an **Include** rule with the **Emails** selector and the approved individual addresses. Use **Emails ending in** only when everybody who can obtain an address at that domain should have access. Never allow a public email provider's entire domain. 6. Set the policy's **Session duration** to your chosen limit, or let it inherit the application setting. Our example uses eight hours for normal staff access; this is an administrative choice. 7. Save the policy. Open **Zero Trust > Access controls > Applications > Create new application > Self-hosted and private > Add public hostname**. 8. Select your domain and enter the staging subdomain. Leave the path empty to protect the entire hostname. 9. Under **Access policies**, attach the staging policy. Enable **One-time PIN** as this application's login method. 10. Set **Session Duration** to eight hours, then select **Create**. Repeat for the wiki with its own policy and allowed addresses. 11. Under **Zero Trust > Access controls > Access settings > Set your global session duration**, choose eight hours if you also want the remembered identity to expire that day. A shorter application session alone can renew silently while the global session remains valid. Do not add an **Everyone** rule or a **Bypass** policy for convenience. Review all rules attached to an application, including reusable policies shared with other applications. Sources: [One-time PIN](https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/), [policy management](https://developers.cloudflare.com/cloudflare-one/access-controls/policies/policy-management/), [Access policy selectors](https://developers.cloudflare.com/cloudflare-one/access-controls/policies/), [self hosted applications](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/), [session management](https://developers.cloudflare.com/cloudflare-one/access-controls/access-settings/session-management/). ## 5. Install cloudflared from the official repository Run these commands on the server. The `any` repository is Cloudflare's current Debian and Ubuntu example. Sources: [Cloudflare package repository](https://pkg.cloudflare.com/) and [official installation instructions](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/create-local-tunnel/), read October 29, 2026. ```sh sudo mkdir -p --mode=0755 /usr/share/keyrings curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list sudo apt-get update sudo apt-get install cloudflared cloudflared --version ``` ## 6A. Recommended: a remotely managed tunnel Use this option when the dashboard is easier for your small team to maintain. Cloudflare stores its configuration. A tunnel token lets the connector run; keep it secret. 1. In the Cloudflare dashboard open **Networking > Tunnels > Create a tunnel**. 2. Give the tunnel a useful name and select **Create Tunnel**. 3. Choose the server's operating system and use the displayed installation command. With the package already installed, the service command has this form. Sources: [dashboard tunnel setup](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/) and [tunnel token permissions](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/remote-tunnel-permissions/). ```sh sudo cloudflared service install '' sudo systemctl status cloudflared ``` 4. Wait for the connector to connect and select **Continue**. 5. Select the tunnel, then **Routes > Add route > Published application**. 6. Enter `staging` and your domain. Set **Service URL** to `http://localhost:8080`. Select **Add route**. Add the wiki route pointing to `http://localhost:8081`. 7. Enable **Protect with Access** for each HTTP route's origin settings, using that application's audience tag and your team name as requested. This makes `cloudflared` validate the Access JWT before forwarding the request. The alternative is to implement and test JWT validation in the application itself. 8. Confirm the tunnel displays **Healthy**. Continue to step 7 below. Sources: [published application routes](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/), [Access origin settings](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/origin-parameters/). A working tunnel alone does not restrict visitors; the Access applications created in step 4 do that. ## 6B. Alternative: a locally managed tunnel Choose this when a developer will maintain the configuration file. Cloudflare still provides the service; “locally managed” describes where configuration lives. Perform this alternative instead of step 6A. Authenticate and create the tunnel from the server's named administrator account. Open the displayed authorization URL on your own computer if the server has no browser. These commands create Cloudflare resources and credentials when you run them. Source: [locally managed tunnel guide](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/create-local-tunnel/). ```sh cloudflared tunnel login cloudflared tunnel create dev-preview ``` Record the generated tunnel UUID. The login creates an account certificate, `cert.pem`; tunnel creation creates a separate tunnel credential JSON file. The account certificate has broader management authority. Keep both private and keep credentials out of version control. Create `/etc/cloudflared` as a root owned directory. Copy only this tunnel's credential JSON from the location reported by the create command into that directory, with root ownership and mode `0600`. These file operations assume the default credential location; substitute the actual path if the create command reported another one. Sources: [local tunnel credentials](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/create-local-tunnel/) and [Ubuntu install command manual](https://manpages.ubuntu.com/manpages/noble/en/man1/install.1.html). ```sh sudo install -d -m 0700 /etc/cloudflared sudo install -m 0600 "$HOME/.cloudflared/.json" '/etc/cloudflared/.json' ``` Save the following as `/etc/cloudflared/config.yml` using your administrator editor. Substitute the UUID, hostnames, team name and each application's AUD tag. The credential path must match where you placed the JSON file. Sources: [configuration file](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/configuration-file/), [Access JWT origin settings](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/origin-parameters/), [Linux service](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/as-a-service/linux/). ```yaml tunnel: credentials-file: /etc/cloudflared/.json ingress: - hostname: staging.example.com service: http://localhost:8080 originRequest: access: required: true teamName: audTag: - - hostname: wiki.example.com service: http://localhost:8081 originRequest: access: required: true teamName: audTag: - - service: http_status:404 ``` The final catch all rule is required. It returns 404 for a hostname that does not match either application. Hostname rules cover the whole hostname, avoiding unnecessary path policy complexity. Validate the file and check all three routing outcomes. These commands inspect the local configuration; they do not start a tunnel. Source: [ingress validation and matching](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/configuration-file/). ```sh sudo cloudflared tunnel --config /etc/cloudflared/config.yml ingress validate sudo cloudflared tunnel --config /etc/cloudflared/config.yml ingress rule https://staging.example.com sudo cloudflared tunnel --config /etc/cloudflared/config.yml ingress rule https://wiki.example.com sudo cloudflared tunnel --config /etc/cloudflared/config.yml ingress rule https://unmatched.example.com ``` Create DNS routes after the Access applications exist. These commands use the account certificate created at login. Source: [local tunnel routing](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/create-local-tunnel/). ```sh cloudflared tunnel route dns '' staging.example.com cloudflared tunnel route dns '' wiki.example.com ``` Install the service with the explicit configuration path, avoiding a different home directory under sudo. Start it and check its status. Do not install a second competing service if step 6A already installed one. Source: [Cloudflare Linux service instructions](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/as-a-service/linux/). ```sh sudo cloudflared --config /etc/cloudflared/config.yml service install sudo systemctl start cloudflared sudo systemctl status cloudflared ``` ## 7. Test the web applications - [ ] Open `https://staging.example.com` in a private browser window. The first page must be Cloudflare Access, without application content. - [ ] Enter an approved email and select **Send login code**. Enter the fresh code and select **Sign in**. Verify the expected application loads. - [ ] Repeat for the wiki. A staging reviewer who is not allowed into the wiki must be denied there. - [ ] Use an unapproved address you control. It must not receive application access. Cloudflare deliberately displays a generic “code emailed” message even when it sends no code. - [ ] Test a logged out request without a service token. No application content should be returned. - [ ] Verify direct access to the server's public address and each application port fails, for both enabled IP families. Test from another network, not only from inside the server. - [ ] Verify the provider recovery method works. Then reboot during an agreed window and confirm the tunnel and applications return. - [ ] Create a backup, restore it into a separate test instance and verify a record and a file. Record who performed the check and the next due date. OTP codes expire after ten minutes, are single use, and requesting a new code invalidates the previous code. Source: [One-time PIN behavior](https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/). ## 8. Give CI a service token A script cannot enter an email code. Give each automation its own credential and a narrowly scoped application policy. 1. Open **Zero Trust > Access controls > Service credentials > Service Tokens**. 2. Select **Create Service Token**, name the job and choose its duration. 3. Save the Client ID and Client Secret in your CI secret store. The secret is shown only at creation. 4. Create a separate policy with **Action: Service Auth**, **Include: Service Token**, and that specific token. Attach it only to the required application. 5. Send both headers on every automated request. Replace the placeholders from the secret store; never put real values in a committed script. Source: [Cloudflare service tokens](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/service-tokens/), read October 29, 2026. ```sh curl --fail \ -H 'CF-Access-Client-Id: ' \ -H 'CF-Access-Client-Secret: ' \ https://staging.example.com/ ``` Test the same endpoint without headers and with a deliberately invalid token. Both should be denied. Do not use a broad **Bypass** policy for CI. A service token grants entry through Access; the application's own authorization still decides what the automation may do. Delete the token when retiring the job. Revoking sessions alone does not invalidate a still valid service token. ## 9. Optional: put SSH behind Access Keep the provider console and the current SSH session available. First create a separate Access application for `ssh.example.com`, with an **Allow** policy containing only administrator emails. Then add a tunnel **Published application** route with **Service: SSH** and destination `localhost:22`. For a locally managed tunnel, add an SSH hostname rule with `service: ssh://localhost:22` before the catch all rule and add its DNS route. The HTTP JWT origin setting in step 6B is for HTTP applications; do not copy it blindly to SSH. Install `cloudflared` on your own computer using Cloudflare's instructions. In your computer's SSH configuration, add the following, replacing the executable path if your installation uses another path. Source: [SSH with client side cloudflared](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/use-cases/ssh/ssh-cloudflared-authentication/), read October 29, 2026. ```sshconfig Host ssh.example.com ProxyCommand /usr/bin/cloudflared access ssh --hostname %h ``` Connect from your computer. The browser opens for Access authentication; the SSH server still authenticates your Linux account using its SSH configuration. Source: [Cloudflare SSH connection instructions](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/use-cases/ssh/ssh-cloudflared-authentication/). ```sh ssh devadmin@ssh.example.com ``` The browser terminal is another option. Cloudflare documents **Applications > Configure > Allow access through browser-based RDP, SSH, or VNC sessions > SSH**. It requires a public hostname, supports only Allow or Block policies, and requires the email prefix to match the server username. Follow its separate SSH authentication requirements before choosing it. Do not weaken key based SSH merely to enable a browser terminal. Source: [browser rendered terminal](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/non-http/browser-rendering/). After a new tunnel based SSH session and the recovery path both work, remove the direct SSH firewall rule if you want no inbound ports. Also remove any obsolete broad allow rules shown in the numbered list; check each rule before deleting it. Source: [Ubuntu firewall rule removal](https://documentation.ubuntu.com/server/how-to/security/firewalls/). ```sh sudo ufw delete allow from '' to any port 22 proto tcp sudo ufw status numbered ``` An Access application session duration does not terminate an already active SSH connection in this mode. During offboarding, end server sessions and remove SSH credentials as well. Source: [session management for SSH](https://developers.cloudflare.com/cloudflare-one/access-controls/access-settings/session-management/). If you lose access, use the provider console or rescue environment. Keep the provider account independent of this server. Kimsufi does **not** include IPMI access; OVHcloud's documented recovery path is rescue mode from its Control Panel. Sources: [Kimsufi getting started](https://support.us.ovhcloud.com/hc/en-us/articles/28143494826259-Getting-started-with-a-Kimsufi-So-You-Start-or-Rise-dedicated-server) and [rescue mode instructions](https://support.us.ovhcloud.com/hc/en-us/articles/115001754490-How-to-activate-and-use-rescue-mode), verified in a regular browser October 29, 2026. For Kimsufi, follow this recovery sequence: 1. Open the server in the **OVHcloud Control Panel**. 2. In **General information**, select the button beside **Boot**, then **Edit**. 3. Under **Change the netboot**, select **Boot in rescue mode** and choose **Customer rescue system** from the drop down. 4. Confirm. Check the notification about the Netboot setting in **General information**. 5. In the **Service status** box, select the button beside **Status**, then **Restart**. This interrupts the running server. 6. Follow the provider's rescue instructions to access the rescue environment and repair the installed system's SSH or firewall configuration. Restore the normal disk boot setting and restart after repairs, then verify a new login. Rehearse access to the Control Panel before closing direct SSH. Rescue mode helps repair the server; it does not replace an off site backup. An OS reinstall can erase data, so treat reinstalling as a separate recovery decision. ## 10. Offboard a person or a client - [ ] Remove their address from every relevant Allow policy, or add an explicit exclusion if a broad company domain rule would otherwise admit them. - [ ] Disable the person's company mailbox or identity provider account. A working mailbox can still receive OTP codes wherever policies allow it. - [ ] Open **Zero Trust > Team & Resources > Users**, select the user, then **Action > Revoke**. Removing access eligibility and revoking existing sessions are both necessary. - [ ] Remove the seat if appropriate after revoking access. Seat removal is not your access control procedure. - [ ] Disable their application account, SSH keys and active shell sessions. Reassign scheduled jobs and repositories. - [ ] Delete service tokens they no longer need; rotate shared secrets they could read, including tunnel tokens when relevant. - [ ] Test a former access route and review recent logs. Record the date and reviewer. Sources: [revoking user sessions](https://developers.cloudflare.com/cloudflare-one/access-controls/access-settings/session-management/), [user management](https://developers.cloudflare.com/cloudflare-one/team-and-resources/users/users/), [service token revocation](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/service-tokens/). ## 11. Keep it working Review **Zero Trust > Insights > Logs > Access authentication logs** for unexpected access. Authentication logs record login events, not every action inside the application. OTP attempts are logged after a code is submitted. Keep application logs too, with a retention policy that fits the data. Sources: [Access logs](https://developers.cloudflare.com/cloudflare-one/insights/logs/dashboard-logs/access-authentication-logs/) and [OTP](https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/). Check `cloudflared` releases during routine maintenance. Cloudflare supports releases within one year of the most recent release. Several releases can arrive in a month; October 2026 had multiple releases, with 2026.10.6 published October 29. Schedule updates rather than treating the support window as a waiting period. Sources: [supported versions](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/) and [official releases](https://github.com/cloudflare/cloudflared/releases). Update an apt installation as follows. Restarting one connector interrupts its traffic, so pick a maintenance window. Source: [update cloudflared](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/update-cloudflared/). ```sh sudo apt-get update sudo apt-get install --only-upgrade cloudflared sudo systemctl restart cloudflared.service sudo systemctl status cloudflared ``` If a tunnel token leaks, open **Networking > Tunnels**, select the tunnel and choose **Overview > Refresh token**. Follow Cloudflare's rotation procedure to replace the tunnel token on every connector. A compromise also requires disconnecting existing unauthorized connections; refreshing the token alone is not enough. Source: [tunnel token rotation and compromise response](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/remote-tunnel-permissions/). Keep encrypted backups off the server, including database exports, uploaded files and the configuration needed to rebuild. Restrict backup credentials and retain an independent recovery copy. Review retention and perform a restore test regularly. Keep production customer data off this development box unless you have a documented security, retention and compliance plan. [Monitoring guidance](https://jwatte.com/blog/apache-monitoring-logging-small-business/) can help you decide what needs an alert. ## Troubleshooting | Symptom | Check | Next action | |---|---|---| | 502 after a successful login | Tunnel is connected but cannot reach the configured origin | Check that the application runs on the configured loopback port and that HTTP versus HTTPS is correct. Check the application logs before changing Access. | | Login loop or page stops after a session expires | Wrong hostname, cookie restrictions, application redirect or expired Access session | Retry a private window, check the application's external URL and Access hostname, and review authentication logs. Do not fix this with a Bypass rule. | | No email code | Address fails the policy, mail filtering, or an old code was superseded | Confirm the exact address is allowed. Check spam and gateway filtering for `noreply@notify.cloudflare.com`. Request one fresh code. | | Code already used | Mail security software may have consumed the link | Review mail filtering with the mail administrator and request a new code. | | Tunnel Down or Inactive | Service stopped, invalid token, or blocked outbound connection | Check the service and outbound port 7844. Verify the connector has the current token. | | Wiki appears for a staging hostname | Wrong route order or hostname | Run the offline ingress rule checks and compare both dashboard routes. | | Service token request reaches a login page | Missing headers or incorrect policy action | Use the exact Client ID and Client Secret header names and a Service Auth policy for that token. | | SSH works through Access but a former user remains connected | Existing SSH session is still active | End the server session and remove its SSH authorization. Application timeout alone does not end it. | | Lockout after firewall change | Administrator address changed or allow rule missing | Recover through the provider console or rescue environment, then retest before closing recovery access. | Sources: [tunnel troubleshooting](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/troubleshoot-tunnels/common-errors/), [OTP](https://developers.cloudflare.com/cloudflare-one/integrations/identity-providers/one-time-pin/), [service tokens](https://developers.cloudflare.com/cloudflare-one/access-controls/service-credentials/service-tokens/), [session behavior](https://developers.cloudflare.com/cloudflare-one/access-controls/access-settings/session-management/), read October 29, 2026. ## Cost worksheet Use US dollars before tax. Record the model, region, setup fee, renewal price and commitment before ordering. Stock is part of the decision: an unavailable server cannot launch the project. | Input | Your low case | Your high case | |---|---|---| | Users needing Access | Fill in | Fill in | | Server monthly charge | Fill in | Fill in | | Provider setup fee | Fill in | Fill in | | Setup hours | Fill in | Fill in | | Monthly administration hours | Fill in | Fill in | | Total retained backup GB | Fill in | Fill in | | Monthly backup download GB | Fill in | Fill in | | Managed alternative and scope | Fill in | Fill in | Loaded labor = $68.09 per hour. This is an employee compensation proxy, not a contractor quote. One server planning range = 4 to 12 setup hours plus 1 to 3 administration hours monthly. Off site backup storage uses Backblaze B2 at $6.95 per decimal TB monthly with the first 10 GB free. For our assumed 50 to 200 GB retained, storage is $0.278 to $1.3205 monthly before display rounding. Extra usage and provider transfer charges can add cost. Setup = provider setup fee + setup hours × $68.09. Monthly = hosting + Access seats + backup storage and usage + administration hours × $68.09. 36 month total = setup + 36 × monthly. Savings = managed alternative total minus self hosted total. When self hosting has lower monthly cost, break even month = ceiling((self hosted setup minus alternative setup) / (alternative monthly minus self hosted monthly)), with a minimum of zero. If monthly cost is higher and setup offers no advantage, write “never.” Here are the article's worked numbers. Our assumptions are one server, 2 to 10 users, 50 to 200 GB of retained backups, and one stateless preview application. The Kimsufi row uses the listed KS-5 price of $20 monthly plus a $20 installation fee. The configurator showed US West, Hillsboro, available when checked October 29, 2026. Commitment terms were not visible without proceeding to the cart, so check the commitment term and setup fee at checkout. Stock and the final configuration can change the purchase decision. DigitalOcean uses the $24 Basic Regular 4 GiB tier. Cloudflare Free contributes $0 in both server rows. The managed comparison is Render Pro at $25 monthly plus one Pro 2c-4g service at $85 monthly, totaling $110. Our managed labor assumption is 1 to 3 setup hours and 0.25 to 0.75 hours monthly. This smaller labor allowance assumes a supported stateless application. Access control still needs a separate design; Render is not the identical package. Backblaze storage in all rows holds independently uploaded source artifacts and test fixtures. Render persistent disks, databases, excess usage and additional preview instances are excluded. | Option | Setup, low to high | Monthly, low to high | 36 months, low to high | |---|---:|---:|---:| | Kimsufi KS-5, listed price | $292 to $837 | $88 to $226 | $3,474 to $8,958 | | DigitalOcean 4 GiB VPS | $272 to $817 | $92 to $230 | $3,598 to $9,082 | | Render Pro plus one 4 GB service | $68 to $204 | $127 to $162 | $4,651 to $6,050 | Calculations use unrounded intermediate values. For example, the VPS low case is `4 × 68.09 + 36 × (24 + 0.278 + 1 × 68.09) = 3597.608`, displayed as $3,598. Compared with the corresponding Render case, KS-5 saves $1,177 in the low labor case and costs $2,908 more in the high case. The VPS saves $1,053 low and costs $3,032 more high. Low case break even is month 6 for either server. High case break even is never for either server. The managed service wins the high labor comparison, and can be the better purchase whenever nobody has time to maintain the server. Offer sources: [Kimsufi US catalog](https://eco.us.ovhcloud.com/kimsufi/), [DigitalOcean Droplets](https://www.digitalocean.com/pricing/droplets), [Render pricing](https://render.com/pricing), read October 29, 2026. Confirm the Kimsufi price, stock and commitment before relying on that row. Sources: [BLS administrator wages](https://data.bls.gov/oesprofile/?areas=INDUSTRY,STATE,MSA&major_group=150000&measure=01&occupation=151244&year=2025), [BLS compensation share](https://data.bls.gov/timeseries/CMU2020000000000P), [DigitalOcean pricing](https://www.digitalocean.com/pricing/droplets), [Backblaze B2 pricing](https://www.backblaze.com/cloud-storage/pricing), [Cloudflare Zero Trust pricing](https://www.cloudflare.com/plans/zero-trust-services/), read October 29, 2026. ## Validation and source dates The sample configuration was checked offline with `cloudflared` 2026.10.3. Ingress validation passed; staging matched rule 0, wiki matched rule 1, and an unmatched hostname matched the 404 catch all. These checks validate configuration syntax and routing selection. They do not verify your DNS, credentials, Access policy, application, SSH access or backup recovery. Complete the test checklist on your own new server before using real data. Cloudflare developer documentation and Ubuntu documentation linked beside the instructions were read October 29, 2026. Pricing inputs were checked on that date. Recheck vendor pages before purchase and the linked setup documentation before installation. *Cloudflare, Kimsufi, OVHcloud and other product names identify the products discussed. This site is not affiliated with or endorsed by those providers.*