Skip to content

Instantly share code, notes, and snippets.

@AnthonyWharton
Last active March 9, 2024 13:40
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save AnthonyWharton/a0e8faae7195a5c1dea210466eda1c92 to your computer and use it in GitHub Desktop.
Save AnthonyWharton/a0e8faae7195a5c1dea210466eda1c92 to your computer and use it in GitHub Desktop.
FreeDNS (afraid.org) Cerbot/Let's Encrypt Manual Automation Script
#!/bin/bash
# Copyright 2018, Anthony Wharton
# Single script that can be called that generates certificates using the
# certbotFreeDNSAuthHook.sh and certbotFreeDNSCleanupHook.sh scripts.
# This should be used as guidence of my usage, and changed to your needs. Note
# the generic `/path/to/...` and `DOMAIN.COM`, which should be replaced with
# your script location and domain respectively. In addition, for this to be
# used on a live system, one must remove the `--dry-run` flag.
certbot certonly \
--dry-run \
--agree-tos \
--manual-public-ip-logging-ok \
--renew-by-default \
--manual \
--preferred-challenges=dns \
--manual-auth-hook /path/to/certbotFreeDNSAuthHook.sh \
--manual-cleanup-hook /path/to/certbotFreeDNSCleanupHook.sh \
-d "DOMAIN.COM" \
-d "*.DOMAIN.COM" \
--server https://acme-v02.api.letsencrypt.org/directory
#!/bin/bash
# Copyright 2018, Anthony Wharton
# Script that logs into FreeDNS.afraid.org and puts in the _acme-challenge TXT
# record as required by certbot for let's encrypt certificates.
# This was made for my need to automate wildcard renewals which cannot work
# automatically.
# TODO: Update to your FreeDNS.afraid.org username and password.
USERNAME='user%40domain.com' # Username for FreeDNS
PASSWORD='verysecurepassword' # Password for FreeDNS
WORKINGDIR="/tmp/CERTBOT_$CERTBOT_DOMAIN"
COOKIEFILE="$WORKINGDIR/cookies.tmp"
TXTID_FILE="$WORKINGDIR/TXT_ID"
REGEX_DOMAINID="s/.*$CERTBOT_DOMAIN.*domain_id=\\([0-9]*\\).*/\\1/;t;d"
REGEX_TXTID="s/.*data_id=\\([0-9]*\\)>_acme-challenge.*/\\1/;t;d"
echo "==============================================="
if [ ! -d $WORKINGDIR ]; then
echo "Creating working director for temporary files ($WORKINGDIR)"
mkdir -m 0700 $WORKINGDIR
fi
echo "Logging in..."
curl -s "https://freedns.afraid.org/zc.php?step=2 " \
-c $COOKIEFILE \
-d "action=auth" \
-d "submit=Login" \
-d "username=$USERNAME" \
-d "password=$PASSWORD"
echo "Getting domain ID..."
DOM_ID=$(curl -s "https://freedns.afraid.org/subdomain/" \
-b $COOKIEFILE \
| sed --posix $REGEX_DOMAINID)
echo "Domain ID: $DOM_ID"
echo "Getting current TXT record ID (if existent)..."
TXT_ID=$(curl -s "https://freedns.afraid.org/subdomain/" \
-b $COOKIEFILE \
| sed --posix $REGEX_TXTID)
echo "Creating/Updaing TXT record..."
curl -s "https://freedns.afraid.org/subdomain/save.php?step=2" \
-b $COOKIEFILE \
-d "type=TXT" \
-d "subdomain=_acme-challenge" \
-d "domain_id=$DOM_ID" \
-d "address=%22$CERTBOT_VALIDATION%22" \
-d "data_id=$TXT_ID" \
-d "send=Save%21"
TXT_ID=$(curl -s "https://freedns.afraid.org/subdomain/" \
-b $COOKIEFILE \
| sed --posix $REGEX_TXTID)
echo "TXT record ID: $TXT_ID"
echo Saving ID for cleanup...
echo $TXT_ID > $TXTID_FILE
echo "Auth Step DONE, Sleeping to allow for DNS records to propagate"
sleep 15
echo "==============================================="
#!/bin/bash
# Copyright 2018, Anthony Wharton
# Script that logs into FreeDNS.afraid.org and cleans up the _acme-challenge
# TXT record as created by the certbotFreeDNSAuthHook.sh script.
# This was made for my need to automate wildcard renewals which cannot work
# automatically.
# TODO: Update to your FreeDNS.afraid.org username and password.
USERNAME='user%40domain.com' # Username for FreeDNS
PASSWORD='verysecurepassword' # Password for FreeDNS
WORKINGDIR="/tmp/CERTBOT_$CERTBOT_DOMAIN"
COOKIEFILE="$WORKINGDIR/cookies.tmp"
TXTID_FILE="$WORKINGDIR/TXT_ID"
echo "==============================================="
echo "Cleaning up..."
if [ ! -f $COOKIESFILE ]; then
echo "No saved cookies found... Logging in..."
curl -s "https://freedns.afraid.org/zc.php?step=2 " \
-c $COOKIEFILE \
-d "action=auth" \
-d "submit=Login" \
-d "username=$USERNAME" \
-d "password=$PASSWORD"
fi
if [ -f $TXTID_FILE ]; then
TXT_ID=$(cat $TXTID_FILE)
echo "Deleting TXT record ID ($TXT_ID)..."
QUERY="https://freedns.afraid.org/subdomain/delete2.php?"
QUERY+="data_id%5B%5D=$TXT_ID&"
QUERY+="submit=delete+selected"
curl -s $QUERY -b $COOKIEFILE
fi
rm -vrf $WORKINGDIR
echo "DONE"
echo "==============================================="
@dreamwraith
Copy link

Seems to be some error with the regex thats resulting in it creating the txt record on the wrong domain when you have multiple domains.

@dreamwraith
Copy link

Change the regex for DOMAINID as follows:
REGEX_DOMAINID="s~.*<td>$CERTBOT_DOMAIN</td><td[[:space:]]align=right><a[[:space:]]href=/subdomain/edit\\.php\\?edit_domain_id=\\([0-9]*\\)>\\[[[:space:]]add[[:space:]]\\]</a></td></tr>.*~\\1~;t;d"

@neil-bh
Copy link

neil-bh commented Aug 21, 2020

Hi, in your comment you let people know they need to substitute /path/to/... and DOMAIN.COM respectively. However I was still having problems running the script. I found that I also had to hardcode the $CERTBOT_DOMAIN variable just before it is used in the $WORKING_DIR variable:

CERTBOT_DOMAIN="hello.mydomain.com"
WORKINGDIR="/tmp/CERTBOT_$CERTBOT_DOMAIN"

I made this change in both the certbotFreeDNSAuthHook.sh and certbotFreeDNSCleanupHook.sh scripts.

@AnthonyWharton
Copy link
Author

@wizzkid Are you running the scripts manually or as hooks? CERTBOT_DOMAIN should be populated by certbot when it runs the script as a hook:

https://certbot.eff.org/docs/using.html (Search for “CERTBOT_DOMAIN”)

@dreamwraith
Copy link

Just recently this stopped working and I can't quite determine why. automatedManualCertbotRenewal.sh no longer runs properly with multiple domains specified. It ends up failing with having the wrong TXT record loaded. It seems as though it does both text records before the first verify even runs, and then fails out or something.

Trying to debug but haven't figured a solution yet.

@AnthonyWharton
Copy link
Author

AnthonyWharton commented Nov 9, 2020

@dreamwraith Hmm ok, not sure if anything has changed with certbot or FreeDNS to cause this to break as it’s a little bit of an old script now; I’ll try have a look at some point if I get some time.

Unfortunately I’m quite busy with other projects and not actively using this any more so I can’t make any promises. I see you suggested some regex changes in the past (sorry I never got round to testing them so didn’t feel I could comment), something similar may be required depending on if FreeDNS has updated!

@dreamwraith
Copy link

No worries, appreciate the response. I will look into it and see if I can figure out. Just a hobby project for me as well.

@la1o
Copy link

la1o commented Jan 19, 2021

@dreamwraith
Copy link

@la1o @AnthonyWharton

I personally ended up switching to https://github.com/acmesh-official/acme.sh which works swimmingly well now. Thanks for your original script getting me by before we had solid solutions Anthony.

la1o, perhaps you could report that token/edit form info to the acme.sh folks? Not sure if they have worked it into their current code yet. Pretty sure it still uses the "older" methods, but works somehow.

@AnthonyWharton
Copy link
Author

That’s quite alright! That project looks very neat.. and maintained which is definitely something ha ha!

With the small amount of certbot work I’ve done recently I’ve also found that web based authentication works a lot quicker and more reliably as opposed to with DNS records! I think the only limitation might have been the wildcard cert, which is why I wrote this... but to be honest I’ve not touched it in a long while and forgotten! Sorry for the lack of maintenance!

@dmiller423
Copy link

How do you get acme.sh to work for a subdomain?

@Kornelius777
Copy link

Thank you for a great script!
I had do extend the waiting period (instead of 15 seconds, I wait 115 seconds).
And I chose to replace "--renew-by-default" by "--keep-until-expiring".
However, apart from that: GREAT! Thank you again!

@politick
Copy link

Change the regex for DOMAINID as follows:
REGEX_DOMAINID="s~.*<td>$CERTBOT_DOMAIN</td><td[[:space:]]align=right><a[[:space:]]href=/subdomain/edit\\.php\\?edit_domain_id=\\([0-9]*\\)>\\[[[:space:]]add[[:space:]]\\]</a></td></tr>.*~\\1~;t;d"

Yes !!
Same here. I have multiple domain names and it's picking the wrong one (probably the last one.)
So the record was appearing in the wrong domain.

@alanmilinovic
Copy link

How do you get acme.sh to work for a subdomain?

I am wondering the same. Also this script is not working, with modified Regex same result.

@AnthonyWharton
Copy link
Author

This project is not maintained, to be honest it might as well be categorised as dilapidated. I wrote it 5 years ago. I'm not sure I can even remember exactly why I wrote this instead of using certbot - perhaps functionality in certbot these days didn't exist back then, or perhaps I simply didn't know about it and wanted to have some fun and try make something myself.

These days I would look at using certbox with the nginx plugin; it's really quick and easy as it verifies using nginx as a web server, and will easily allow you to handle subdomains. The script above is pretty ugly in comparison, manually logging into and scraping the FreeDNS website with credentials to verify the domain using DNS - there's loads that is hardcoded, and verifying with DNS is in most cases slower.

Here's some guides found with a very quick search online (I've not been through and tried these command for command, but from a high level they look ok):

@politick
Copy link

politick commented Mar 8, 2024

Acme.sh now supports freedns.org natively.
https://github.com/acmesh-official/acme.sh

This is how I've used acme.sh to get certs from LetsEncrypt using FreeDns.org:
https://www.politick.ca/en/DevOps/LetsEncrypt

@alanmilinovic
Copy link

Thank you both for your response but as mentioned it is not working for subdomains.

@alanmilinovic
Copy link

[Fr 8. Mär 21:08:01 CET 2024] Domain 1nuc.mooo.com not found at FreeDNS, try with next level of TLD
[Fr 8. Mär 21:08:02 CET 2024] Domain mooo.com found at FreeDNS, domain_id 29
[Fr 8. Mär 21:08:02 CET 2024] FreeDNS failed to add TXT record for _acme-challenge.1nuc as FreeDNS requested security code
[Fr 8. Mär 21:08:02 CET 2024] Note that you cannot use automatic DNS validation for FreeDNS public domains
[Fr 8. Mär 21:08:02 CET 2024] Error add txt for domain:_acme-challenge.1nuc.mooo.com
[Fr 8. Mär 21:08:02 CET 2024] Please add '--debug' or '--log' to check more details.
[Fr 8. Mär 21:08:02 CET 2024] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

@alanmilinovic
Copy link

alanmilinovic commented Mar 8, 2024

It is really a pity. Is there any other approach that can be applied?

@AnthonyWharton
Copy link
Author

@politick Someone linked acme.sh earlier and it looks great!

@alanmilinovic I'm not familiar enough with acme.sh to help as I've only looked at the project from a high level and not used it. Perhaps someone from their community could help you if you raise an issue - although I would take some time to put all relevant information in the issue to make it as easy as possible for people to help you. Remember people respond to things in their own time, so if you can simplify their life by providing them all the facts, you'll be more likely to have someone spot what is wrong and then get good support/advice.

What I would say is that from personal experience I know subdomains work fine with nginx/certbot, so I would explore that perhaps instead if you are having trouble with acme.sh?

@politick
Copy link

politick commented Mar 8, 2024

I've looked at using subdomains a couple of times in the past (to join family houses together with VPNs and each have their subdomain and DNS SOA).

But that does not typically fall under a "Normal DIY" network configuration so all the "Free & DIY" services and programs don't consider that use case. That use case will typically fall under big corporations and can just throw $$$ at it and have their solution.

So I've found other methods to address my DIY networking problem to VPN and maintain DNS. Essentially a subdomain is one solution to a problem, there might be other ways to achieve your end goal.

Kind Regards, Martin Politick, 2024.

@alanmilinovic
Copy link

I've looked at using subdomains a couple of times in the past (to join family houses together with VPNs and each have their subdomain and DNS SOA).

But that does not typically fall under a "Normal DIY" network configuration so all the "Free & DIY" services and programs don't consider that use case. That use case will typically fall under big corporations and can just throw $$$ at it and have their solution.

So I've found other methods to address my DIY networking problem. Kind Regards, Martin Politick, 2024.

I have exactly the same thing, I am doing this for my family house as well.

Can you share what are that other methods you used?

@dreamwraith
Copy link

dreamwraith commented Mar 8, 2024 via email

@politick
Copy link

politick commented Mar 8, 2024

@alanmilinovic They are all homebrew scripts. Again it depends what problem you're trying to resolve. You've not stated your current problem, and I would have to assume that 'vpn' is likely your end goal.

I'm not sure this place is the right location to document this, but part of your solution is for each house to monitor their public addresses and update them with freeDNS API:

curl  "https://freedns.afraid.org/dynamic/update.php?<MY_VERY_OWN_SECRET_FOR_ONE_ENTRY>=" 

and configure FreeDNS to update Link updates of the same IP together? Currently ON if you have more than one name pointing at the same house.

I also have automated scripts to edit my local DNS ( the DNS that serve my computers on my intra-net that are configured to serve different resolutions depending on the IP subnet that requests it. Public / intranet / segregated nets)
Kind Regards, Martin Politick, 2024.

@alanmilinovic
Copy link

Thank you all for responding. I will try to explain my case. So I have free subdomain on freedns.afraid.org where I am updating IP with a cron job regularly. Entire machine is under VPN, so on VPN backend I have some ports that I forward to be able to reach all my applications from outside. That is all working perfectly fine for http but what I would like to use is https and I don't know how to accomplish it with free public subdomain. Tried so far acme.sh and certbot.

@politick
Copy link

politick commented Mar 8, 2024

If you are trying to use a DNS-01 challenge to get a wildcard *.freedns.afraid.org certificate, then you will NOT be able to do so because you don't own the root domain name "afraid.org". Just not possible, because it would be unsafe.

But you should be able to use an HTTP-01 challenge for your alanmilinovic.freedns.afraid.org name as long as you have port 80 forwarded to the web server where you are running the ACME client. This will give you one certificate per "server" name that you can use only on that "single server" ( you can / should use ReverseProxy functionality from that single name to get to all your internal services).
Kind Regards, Martin Politick, 2024.

@alanmilinovic
Copy link

If you are trying to use a DNS-01 challenge to get a wildcard *.freedns.afraid.org certificate, then you will NOT be able to do so because you don't own the root domain name "afraid.org". Just not possible, because it would be unsafe.

But you should be able to use an HTTP-01 challenge for your alanmilinovic.freedns.afraid.org name as long as you have port 80 forwarded to the web server where you are running the ACME client. This will give you one certificate per "server" name that you can use only on that "single server" ( you can / should use ReverseProxy functionality from that single name to get to all your internal services). Kind Regards, Martin Politick, 2024.

Unfortunately, because of VPN, I am not able to port forward port 80.

@dreamwraith
Copy link

dreamwraith commented Mar 8, 2024 via email

@alanmilinovic
Copy link

Do you not control the network at all? If so, it doesn't seem like you should really be concerned with this. I guess I'm just confused. If this is your own personal VPN, you don't need a valid public cert to use https inside your already secured VPN, you can just self sign.

On Fri, Mar 8, 2024, 3:33 PM Alan @.> wrote: @.* commented on this gist. ------------------------------ If you are trying to use a DNS-01 challenge to get a wildcard *. freedns.afraid.org certificate, then you will NOT be able to do so because you don't own the root domain name "afraid.org". Just not possible, because it would be unsafe. But you should be able to use an HTTP-01 challenge for your alanmilinovic.freedns.afraid.org name as long as you have port 80 forwarded to the web server where you are running the ACME client. This will give you one certificate per "server" name that you can use only on that "single server" ( you can / should use ReverseProxy functionality from that single name to get to all your internal services). Kind Regards, Martin Politick, 2024. Unfortunately, because of VPN, I am not able to port forward port 80. — Reply to this email directly, view it on GitHub https://gist.github.com/AnthonyWharton/a0e8faae7195a5c1dea210466eda1c92#gistcomment-4978412 or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJIPCAFNZCAOVT5UQBMFT3YXJDETBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVA4TEMBVGUZDAONHORZGSZ3HMVZKMY3SMVQXIZI . You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .

It is not my personal VPN, and some of the ports are already taken by other users that also subscribed for the same service.

@alanmilinovic
Copy link

So I finally sort it our. Solution was to use Dynu free dns, where I was able to use acme.sh and generate certificate for subdomains. freedns.afraid.org is not supporting subdomains.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment