└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # How to use Tailscale with a custom domain via Cloudflare and reverse proxy on a Synology NAS 2 | 3 | ## Introduction 4 | I recently decided enough is enough, I want to access my self-hosted services while I'm on the go. A lot of people's first thought to accomplish this is **Tailscale**, a service where you can create a private network "bubble" of your chosen devices (called a Tailnet), which can be accessed via an oauth of your choosing. Upon signing up, you're given a unique subdomain, such as `tailb12345.ts.net`, which is used for DNS. As such, you can access your devices using this name instead of an IP address. 5 | 6 | That's great and all, but I had wondered if I could take this a step further and use my own domain to access my devices. So, here we are. "But Jack" I hear you say, "Won't it be secure anyway if we're connecting through Tailscale?". And to that I say, well yes! But this method does come with a couple of benefits: 7 | - Not having to remember which port is which since it'll all be handled via reverse proxy 8 | - Not having to remember (frankly ugly) domain names 9 | 10 | ## Prerequisites 11 | - A Synology NAS 12 | - Docker installed on your NAS 13 | - A domain managed via Cloudflare 14 | - The ability to SSH into your NAS 15 | 16 | ## Initial setup 17 | First off, you'll need to install Tailscale on your Synology NAS. There's a great video by Tailscale's YouTube channel that explains step-by-step how to install Tailscale, configure auto-update, and enable HTTPS: https://www.youtube.com/watch?v=0o2EhK-QvmY 18 | 19 | Once you think you've got it set up, give it a test by going to `https://[nas name].[tailnet name].ts.net`. In my case, my nas is called `ds920`, and my tailnet name is `tailb12345`. 20 | ![brave_waKsC06BDN](https://github.com/user-attachments/assets/0099ef25-376f-4672-aec1-59129f2593f2) 21 | And, we have a successful connection to our machine over HTTPS. 22 | Screenshot 2024-12-19 at 15 05 14 23 | 24 | ## Custom domain with wildcard 25 | Now comes the fun part! We're going to use **Certbot** to get us a wildcard certificate by using the Cloudflare API to complete the DNS-01 challenge. 26 | 27 | ### Generating a Cloudflare API token 28 | 29 | 1. Create a User API token. 30 | 31 | Go to My Profile > API Tokens > Create Token. Give it whatever name you desire, and set parameters like so: 32 | - Permissions: 33 | - Zone: Zone: Read 34 | - Zone: DNS: Edit 35 | - Zone Resources: 36 | - Include: Specific zone: `domain.com` (where `domain.com` is your domain) 37 | 38 | Your summary should look like this: 39 | Screenshot 2024-12-27 at 10 55 09 40 | 41 | 2. Save the API key somewhere, because you won't be able to see it again. 42 | 43 | ### Running Certbot 44 | 45 | This section will assume your volume is called `volume1` and that you have a folder called `docker` inside. Please make necessary adjustments if this doesn't align with your setup. 46 | 47 | 1. SSH into your NAS (if you don't know how to do this on your platform, there are a lot of guides out there) 48 | 2. Create the necessary directories for Certbot: `sudo mkdir -p /volume1/docker/certbot/{logs,lib_letsencrypt,etc_letsencrypt}` 49 | 3. Create the Certbot configuration file: `sudo touch /volume1/docker/certbot/lib_letsencrypt/cloudflare.ini` 50 | 4. Add your Cloudflare API token: 51 | ``` 52 | echo "dns_cloudflare_api_token = your-cloudflare-api-token" | \ 53 | sudo tee /volume1/docker/certbot/lib_letsencrypt/cloudflare.ini > /dev/null 54 | ``` 55 | 5. Use the folling command to launch a temporary Docker container which runs Certbot and adds the necessary DNS records to your domain. Make sure you replace the domains and email with your own. 56 | ``` 57 | sudo docker run --rm \ 58 | -v /volume1/docker/certbot/etc_letsencrypt:/etc/letsencrypt \ 59 | -v /volume1/docker/certbot/lib_letsencrypt:/var/lib/letsencrypt \ 60 | -v /volume1/docker/certbot/logs:/var/log/letsencrypt \ 61 | certbot/dns-cloudflare:latest certonly \ 62 | --dns-cloudflare \ 63 | --dns-cloudflare-credentials /var/lib/letsencrypt/cloudflare.ini \ 64 | --dns-cloudflare-propagation-seconds 30 \ 65 | -d "*.subdomain.domain.com" -d "subdomain.domain.com" \ 66 | --non-interactive --agree-tos --email your-email@example.com 67 | ``` 68 | 69 | 6. If successful, you'll find your new certificates at `.../docker/certbot/etc_letsencrypt/live`. You'll need to download the following files: 70 | - Private Key - `privkey.pem` 71 | - Certificate - `cert.pem` 72 | >A couple of people have reported that their certificates were generated in `.../docker/certbot/etc_letsencrypt/archive` instead of `/live`. 73 | 74 | 7. Import the certificate to your NAS. It'll be in Control Panel > Security > Certificate. Select Add > Add a new certificate > Import certificate > Upload the `Private Key` and `Certificate`. Don't worry about the Intermediate certificate. 75 | 76 | 8. Your certificates page should now look something like this: 77 | ![brave_kpcgyR2F1v](https://github.com/user-attachments/assets/d86cb779-48f8-4c85-9345-b12f1e607d88) 78 | 79 | ## Configure the certificate check script 80 | 81 | Download the certificate check script and run it once to create a configuration file. Then, add your certificate details to the file. 82 | 83 | 1. Download the script and make it executable: 84 | 85 | ```bash 86 | sudo wget -O check_certs.sh https://raw.githubusercontent.com/telnetdoogie/synology-scripts/main/check_certs.sh && \ 87 | sudo chmod +x check_certs.sh 88 | ``` 89 | 2. Run the script to create the configuration file: 90 | 91 | ```bash 92 | sudo ./check_certs.sh 93 | ``` 94 | 95 | 3. Open the configuration file in a text editor and add your certificate's Common Name (CN) and file path: 96 | 97 | ```json 98 | { 99 | "config": [ 100 | { 101 | "cn": "*.subdomain.domain.com", 102 | "cert_path": "/volume1/docker/certbot/etc_letsencrypt/live/domain.com" 103 | } 104 | ] 105 | } 106 | ``` 107 | 108 | ## Schedule certificate renewals 109 | 110 | Let's Encrypt certificates expire every 90 days, but you can automate renewals with the Synology Task Scheduler. To do this, schedule two tasks: one to renew your certificates and another to install them using `check_certs.sh`. 111 | 112 | 1. In Synology DiskStation Manager, go to **Control Panel** > **Task Scheduler**. 113 | 114 | 1. Using **Create** > **Scheduled Task** > **User Defined Script**, add two repeating tasks which run as `root` one hour apart. 115 | 116 | For each task, in the **Task Settings** tab under **Run Command**, enter the following. 117 | 118 | a. For the script to **renew certificates** in the Certbot folder: 119 | 120 | ```bash 121 | /bin/bash 122 | sudo docker run -v /volume1/docker/certbot/etc_letsencrypt:/etc/letsencrypt \ 123 | -v /volume1/docker/certbot/lib_letsencrypt:/var/lib/letsencrypt \ 124 | -v /volume1/docker/certbot/logs:/var/log/letsencrypt \ 125 | --rm \ 126 | --cap-drop=all \ 127 | certbot/dns-cloudflare:latest \ 128 | renew 129 | ``` 130 | b. For the script to **install certificates** on your NAS: 131 | 132 | ```bash 133 | /bin/bash 134 | cd /path/to/script # Change into the script directory 135 | bash /path/to/script/check_certs.sh --update 136 | ``` 137 | 138 | ## Adding Cloudflare CNAME wildcard 139 | Now that we've got a wildcard SSL certificate for our subdomain, we'll need to add a couple of CNAME records which will point our domain towards our Tailnet name. 140 | 1. The first record we'll add will have the following attributes: 141 | - Type: `CNAME` 142 | - Name: `*.subdomain` (a subdomain of your choosing) 143 | - Target: `ds920.tailb12345.ts.net` (where `tailb12345` is your tailnet name and `ds920` is the name of your NAS) 144 | - Proxy status: `DNS Only` 145 | - TTL: `Auto` 146 | 2. The second is optional, but I like to have this as a kind of "home page" where I can link all of my services in one place. 147 | - Type: `CNAME` 148 | - Name: `subdomain` 149 | - Target: `ds920.tailb12345.ts.net` 150 | - Proxy status: `DNS Only` 151 | - TTL: `Auto` 152 | 153 | And that's Cloudflare setup complete! Your DNS records page should look something like this: 154 | ![brave_KEza5JvOuB](https://github.com/user-attachments/assets/210d9017-1b49-4a80-a3d4-19fc3138ecee) 155 | 156 | ## Synology NAS reverse proxy 157 | Since we've only set up a wildcard CNAME record, we still need to tell the NAS where to route a request. One of the amazing showstopping spectacular features of Synology DSM is a built-in reverse proxy manager that's ready to go. We'll be using this to point various sub-subdomains of our choosing to the correct service. In this example, we'll add a reverse proxy to connect to DSM. 158 | 1. Open Control Panel > Login Portal > Advanced > Reverse Proxy 159 | 2. Hit Create 160 | 3. Under General: 161 | - **Source**: 162 | - Name: `dsm` 163 | - Protocol: `HTTPS` 164 | - Hostname: `dsm.subdomain.domain.com` 165 | - Port: `443` 166 | - HSTS: Unchecked 167 | - **Destination**: 168 | - Protocol: `HTTPS` (because we'll be connecting to the secure port 5001) 169 | - Hostname: `localhost` 170 | - Port: `5001` 171 | 4. Hit Save 172 | 5. Add as many services as you desire. **Important: you should only use HTTPS in the destination if you are positive that it's a secure port. If you aren't sure, use HTTP. In most cases, you will be using HTTP.** 173 | Once configured, your reverse proxy list should look something like this: 174 | ![brave_I4qRUgBoUc](https://github.com/user-attachments/assets/0d3ae71a-1df8-4d0f-ad46-33e4ac79ca91) 175 | 6. Now, open back up your certificate settings and set your reverse proxies to use your wildcard SSL certificate: 176 | ![brave_YIf2Arwvmm](https://github.com/user-attachments/assets/ba08973f-6602-427d-89e4-10a86192024e) 177 | 178 | ## Testing 179 | If we've done everything correctly, we should be able to get to each of our services securely (without having to worry about ports!) Let's give it a go with Portainer: 180 | Screenshot 2024-12-27 at 11 18 19 181 | Success! 182 | 183 | > Disclaimer: Some of this guide was copied verbatim from https://github.com/btbristow/tutorials/blob/main/certbot-with-cloudflare.md 184 | --------------------------------------------------------------------------------