dimkr / tootik

A federated nanoblogging service with a Gemini frontend.
gemini://hd.206267.xyz
Apache License 2.0
95 stars 3 forks source link

Listener has failed, address already in use #24

Closed locrianz closed 7 months ago

locrianz commented 7 months ago

Following the quick setup guide, I got as far as running tootik, but I ran into this snag:

{"time":"2023-12-18T02:16:45.351946743Z","level":"INFO","msg":"Collecting garbage"}
{"time":"2023-12-18T02:16:45.352876769Z","level":"INFO","msg":"Starting HTTPS server"}
{"time":"2023-12-18T02:16:45.353559439Z","level":"ERROR","msg":"Gemini listener has failed","error":"listen tcp :1965: bind: address already in use"}
{"time":"2023-12-18T02:16:45.353788972Z","level":"INFO","msg":"Updating poll results"}
{"time":"2023-12-18T02:16:45.355657219Z","level":"ERROR","msg":"Failed to update poll results","error":"context canceled"}
{"time":"2023-12-18T02:16:45.355193575Z","level":"ERROR","msg":"HTTPS listener has failed","error":"listen tcp :443: bind: address already in use"}
{"time":"2023-12-18T02:16:45.355990915Z","level":"WARN","msg":"Failed to accept a connection","error":"accept tcp [::]:79: use of closed network connection"}
{"time":"2023-12-18T02:16:45.356152332Z","level":"WARN","msg":"Failed to accept a connection","error":"accept tcp [::]:70: use of closed network connection"}
{"time":"2023-12-18T02:16:45.356332647Z","level":"ERROR","msg":"Failed to receive a packet","error":"read udp [::]:6775: use of closed network connection"}
{"time":"2023-12-18T02:16:45.356433595Z","level":"INFO","msg":"Shutting down"}
{"time":"2023-12-18T02:16:45.356627584Z","level":"ERROR","msg":"Failed to collect garbage","error":"failed to remove posts by authors without followers: context canceled"}

I do already have ports 443 and 1965 in use by Apache and Agate respectively. I tried using different ports to see what would happen and tootik seemed to run just fine, but when visiting the domain in Gemini I get a TLS/SSL handshake error, and when running curl to test the HTTPS server (or just visiting the address) it directs me to my already-existing website???

Help, what do.

locrianz commented 7 months ago

Actually, visiting the domain redirects me to my extant website even if tootik isn't running. And... so does visiting any other domain I have attached to my Digital Ocean droplet, even if they aren't the domain I specifically set up through Apache. So ignore that complaint, I guess I have to fix that on my own, lol :|

dimkr commented 7 months ago

Exactly as you say, the ports are already in use. You'll need to run tootik with something like -addr :1234 -gemaddr :5678.

https://github.com/dimkr/tootik/wiki/Quick-setup-guide

locrianz commented 7 months ago

I have tried setting the addresses to something else. But as I said, when I did this I got a TLS handshake error on the Gemini side. (I'm having some other weird issue on the HTTPS side that I need to figure out on my own.)

dimkr commented 7 months ago

TLS handshake error on the Gemini side.

What Gemini client did you use? What is the error? What port did you specify in -gemaddr? What port did you browse to using the Gemini client?

locrianz commented 7 months ago

In Lagrange:

TLS/SSL handshake failed - Failed to communicate with the server.

In Bombadillo:

TLS Dial Error: remote error: tls: access denied

In Amfora:

Failed to connect to the server: remote error: tls: access denied

I tried manually adding my chosen port to the domain, and in that case the connection instead simply times out. (It also does this if I try an invalid port that isn't in use at all.)

dimkr commented 7 months ago

Can you share a list of commands you ran to set up your instance, from start to finish? (you can omit domain)

locrianz commented 7 months ago
certbot certonly --standalone
sudo systemctl stop apache2
certbot only --standalone
sudo systemctl restart apache2

lol

mkdir tootik-config
mv tootik-config/ tootik-cfg
cp /etc/letsencrypt/live/[domain]/fullchain.pem tootik-cfg/https-cert.pem
cp /etc/letsencrypt/live/[domain]/privkey.pem tootik-cfg/https-key.pem
mv tootik-cfg/ /tootik-cfg
nano /etc/letsencrypt/renewal-hooks/deploy/tootik.sh
chmod 755 /etc/letsencrypt/renewal-hooks/deploy/tootik.sh
openssl ecparam -name prime256v1 -genkey -out /tmp/ec.pem
openssl req -new -x509 -key /tmp/ec.pem -sha256 -nodes -subj "/CN=[domain]" -out /tootik-cfg/gemini-cert.pem -keyout /tootik-cfg/gemini-key.pem -days 3650
curl -L https://github.com/gardenfence/blocklist/raw/main/gardenfence-mastodon.csv > /tootik-cfg/gardenfence-mastodon.csv
nano /tootik-cfg/gardenfence-mastodon.csv [to see what was in there. yikes.]
mkdir /tootik-data
useradd -mr tootik
chown -R tootik:tootik /tootik-cfg /tootik-data/
curl -L https://github.com/dimkr/tootik/releases/latest/download/tootik -o /usr/local/bin/tootik
ls /usr/local/
mkdir /usr/local/bin
mkdir /usr/local/bin/tootik
curl -L https://github.com/dimkr/tootik/releases/latest/download/tootik -o /usr/local/bin/tootik
rm -r /usr/local/bin/tootik/
curl -L https://github.com/dimkr/tootik/releases/latest/download/tootik -o /usr/local/bin/tootik
chmod 755 /usr/local/bin/tootik
ls /tootik-cfg/
cp /etc/letsencrypt/live/[domain]/fullchain.pem /tootik-cfg/https-cert.pem
cp /etc/letsencrypt/live/[domain]/privkey.pem /tootik-cfg/https-key.pem

I'm not sure how my HTTPS cert and key wound up not being in /tootik-cfg/ there at the end. But that was the last thing I did before I tried running tootik.

First I used this:

tootik -domain [domain] -addr :443 -gemaddr :1965 -gopheraddr :70 -fingeraddr :79 -blocklist /tootik-cfg/gardenfence-mastodon.csv -cert /tootik-cfg/https-cert.pem -key /tootik-cfg/https-key.pem -gemcert /tootik-cfg/gemini-cert.pem -gemkey /tootik-cfg/gemini-key.pem -db /tootik-data/db.sqlite3

Then when I had troubles with the addresses being in use, I switched to this:

tootik -domain [domain] -addr :8443 -gemaddr :8965 -gopheraddr :70 -fingeraddr :79 -blocklist /tootik-cfg/gardenfence-mastodon.csv -cert /tootik-cfg/https-cert.pem -key /tootik-cfg/https-key.pem -gemcert /tootik-cfg/gemini-cert.pem -gemkey /tootik-cfg/gemini-key.pem -db /tootik-data/db.sqlite3
dimkr commented 7 months ago

What does curl -v https://$domain:8443 say?

(I assume CN is wrong because it's $domain and not $domain:8443 in the HTTPS certificate, then similar problem with the Gemini certificate)

locrianz commented 7 months ago
*   Trying [IP address]:8443...
* connect to [IP address] port 8443 failed: Connection timed out
* Failed to connect to [domain] port 8443 after 131413 ms: Connection timed out
* Closing connection 0
curl: (28) Failed to connect to [domain] port 8443 after 131413 ms: Connection timed out
dimkr commented 7 months ago

Does this curl line work if you run it from the same machine and not a remote machine?

locrianz commented 7 months ago

Oh! Yes, it does!

*   Trying [IP address]:8443...
* Connected to [domain] ([IP address) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=[domain]
*  start date: Dec 18 00:45:57 2023 GMT
*  expire date: Mar 17 00:45:56 2024 GMT
*  subjectAltName: host "[domain]" matched cert's "[domain]"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Using Stream ID: 1 (easy handle 0x55edea0d8e90)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET / HTTP/2
> Host: [domain]:8443
> user-agent: curl/7.81.0
> accept: */*
> 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 301 
< location: gemini://[domain]
< content-length: 0
< date: Mon, 18 Dec 2023 16:17:40 GMT
< 
* Connection #0 to host [domain] left intact

Would you recommend I regenerate my certs with :8443 and :8965? I'm not a fan of requiring ports to be specified in URLs, but if that's what I have to do to avoid spinning up another droplet...

dimkr commented 7 months ago

Your problem is probably a firewall or something else that blocks outside traffic to :8443. Wait with re-generating certificates because validation passed in this curl output.

Maybe try this:

iptables -I INPUT -p tcp --dport 8443 -j ACCEPT
iptables -I OUTPUT -p tcp --sport 8443 -j ACCEPT
ip6tables -I INPUT -p tcp --dport 8443 -j ACCEPT
ip6tables -I OUTPUT -p tcp --sport 8443 -j ACCEPT

(or follow https://docs.digitalocean.com/support/check-your-droplet-firewall-settings/ and add a firewall exception for 8443)

Then repeat curl -v https://$domain:8443 from a remote machine.

locrianz commented 7 months ago

curl works from a remote machine now! Navigating to https://domain:8443 in my web browser gives me a Gemini redirect as expected. (Unfortunately, the redirect does not have a port at the end, so Lagrange tries to open it with the default port.)

Trying to visit gemini://domain:8965 in Lagrange gives me a different error now:

Wrong host -- The request was for a resource at a domain not served by the server and the server does not accept proxy requests.
dimkr commented 7 months ago

Are you sure that -domain is correct? For example, in hd.206267.xyz, I pass -domain hd.206267.xyz.

dimkr commented 7 months ago

By the way, I don't think this is going to work. The code uses what you put -domain for everything, including user IDs, and IDs must be valid URLs. Without the port, other servers won't be able to access these URLs.

locrianz commented 7 months ago

Yeah, I'm getting that notion too. (And it seems that certbot isn't even able to generate HTTPS certificates for ports other than 443. Amazing, I love technology.)

Thanks for all the help, I'll just spin up a second droplet for this.

dimkr commented 7 months ago

I took a second look, and I see that tests pass only because they don't rely on incoming requests, and all things that construct object IDs do it the same way (based on domain, without port). Opened #25, which means really supporting a port that's !=443.