As I discussed in Part 1 I've converted this site over to pure IPv6. Well at least as pure as I could get away with. I still have some problems though, chief among them that I cannot send emails with the Ghost CMS. I've switched from Mailgun to Scaleway which does have IPv6 for their SMTP service.
smtp.tem.scw.cloud has IPv6 address 2001:bc8:1201:21:d6ae:52ff:fed0:418e
smtp.tem.scw.cloud has IPv6 address 2001:bc8:1201:21:d6ae:52ff:fed0:6aac
I've also confirmed that my docker-compose stack running Ghost can successfully reach IPv6 external addresses with no issues.
matdevdug-busy-1 | PING google.com (2a00:1450:4002:411::200e): 56 data bytes
matdevdug-busy-1 | 64 bytes from 2a00:1450:4002:411::200e: seq=0 ttl=113 time=15.079 ms
matdevdug-busy-1 | 64 bytes from 2a00:1450:4002:411::200e: seq=1 ttl=113 time=14.607 ms
matdevdug-busy-1 | 64 bytes from 2a00:1450:4002:411::200e: seq=2 ttl=113 time=14.540 ms
matdevdug-busy-1 | 64 bytes from 2a00:1450:4002:411::200e: seq=3 ttl=113 time=14.593 ms
matdevdug-busy-1 |
matdevdug-busy-1 |
matdevdug-busy-1 | --- google.com ping statistics ---
matdevdug-busy-1 | 4 packets transmitted, 4 packets received, 0% packet loss
matdevdug-busy-1 | round-trip min/avg/max = 14.540/14.704/15.079 ms
I've also confirmed that Scaleway is reachable by the container no problem with the domain name, so it isn't a DNS problem.
PING smtp.tem.scw.cloud(ff6ad116-d710-4726-b5d3-1687dceb56cb.fr-par-2.baremetal.scw.cloud (2001:bc8:1201:21:d6ae:52ff:fed0:6aac)) 56 data bytes
64 bytes from ff6ad116-d710-4726-b5d3-1687dceb56cb.fr-par-2.baremetal.scw.cloud (2001:bc8:1201:21:d6ae:52ff:fed0:6aac): icmp_seq=1 ttl=53 time=23.1 ms
64 bytes from ff6ad116-d710-4726-b5d3-1687dceb56cb.fr-par-2.baremetal.scw.cloud (2001:bc8:1201:21:d6ae:52ff:fed0:6aac): icmp_seq=2 ttl=53 time=22.2 ms
64 bytes from ff6ad116-d710-4726-b5d3-1687dceb56cb.fr-par-2.baremetal.scw.cloud (2001:bc8:1201:21:d6ae:52ff:fed0:6aac): icmp_seq=3 ttl=53 time=22.2 ms
64 bytes from ff6ad116-d710-4726-b5d3-1687dceb56cb.fr-par-2.baremetal.scw.cloud (2001:bc8:1201:21:d6ae:52ff:fed0:6aac): icmp_seq=4 ttl=53 time=22.1 ms
--- smtp.tem.scw.cloud ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 22.086/22.397/23.063/0.388 ms
At this point I have three theories.
It's an SMTP problem. Possible, but unlikely given how long SMTP has supported IPv6. A quick check by running it over bash by following the instructions here shows that works fine.
Something is blocking the port.
telnet smtp.tem.scw.cloud 587
Trying 2001:bc8:1201:21:d6ae:52ff:fed0:6aac...
Connected to smtp.tem.scw.cloud.
Escape character is '^]'.
220 smtp.scw-tem.cloud ESMTP Service Ready
"use strict";
const nodemailer = require("nodemailer");
const transporter = nodemailer.createTransport({
host: "smtp.tem.scw.cloud",
port: 587,
// Just so I don't need to worry about it
secure: false,
auth: {
// TODO: replace `user` and `pass` values from <https://forwardemail.net>
user: 'scaleway-user-name',
pass: 'scaleway-password'
}
});
// async..await is not allowed in global scope, must use a wrapper
async function main() {
// send mail with defined transport object
const info = await transporter.sendMail({
from: '"Dead People 👻" <[email protected]>', // sender address
to: "[email protected]", // list of receivers
subject: "Hello", // Subject line
text: "Hello world", // plain text body
html: "<b>Hello world?</b>", // html body
});
console.log("Message sent: %s", info.messageId);
}
main().catch(console.error);
Looks like Nodemailer doesn't seem to understand this is an IPv6 box.
node example.js
Error: connect ENETUNREACH 51.159.99.81:587 - Local (0.0.0.0:0)
at internalConnect (node:net:1060:16)
at defaultTriggerAsyncIdScope (node:internal/async_hooks:464:18)
at node:net:1244:9
at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
errno: -101,
code: 'ESOCKET',
syscall: 'connect',
address: '51.159.99.81',
port: 587,
command: 'CONN'
}
Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: IP: 2001:bc8:1201:21:d6ae:52ff:fed0:6aac is not in the cert's list:
However if you set it to use an IP for host and a DNS entry for hostname, everything seems to work great.
"use strict";
const nodemailer = require("nodemailer");
const transporter = nodemailer.createTransport({
host: "2001:bc8:1201:21:d6ae:52ff:fed0:6aac",
port: 587,
secure: false,
tls: {
rejectUnauthorized: true,
servername: "smtp.tem.scw.cloud"},
auth: {
user: 'scaleway-username',
pass: 'scaleway-password'
}
});
// async..await is not allowed in global scope, must use a wrapper
async function main() {
// send mail with defined transport object
const info = await transporter.sendMail({
from: '"Test" <[email protected]>', // sender address
to: [email protected]", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // html body
});
console.log("Message sent: %s", info.messageId);
}
main().catch(console.error);
It is a little alarming that the biggest Node email package doesn't work with IPv6 and seemingly only one person noticed and tried to fix it. Well whatever, we have a workaround.
Python
Alright let's try to fix the pip problems I was seeing before in various scripts.
pip3 install requests
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.11/README.venv for more information.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
Right I forgot Python was doing this now. Fine, I'll use venv, not a problem. I guess first I compile a version of Python if I want the latest? I don't see any newer ARM packages out there. Alright, compiling Python.
Alright now pip works great on the latest version inside of a venv. My scripts all seem to work fine and there appears to be no issues. Whatever problem there was before is resolved. Specific shoutout to requests where I'm doing some strange things with network traffic and it seems to have no problems.
Conclusion
So the amount of work to get a pretty simple blog up was nontrivial, but we're here now. I have a patch for Ghost that I can apply to the container, Python seems to be working fine/great now and Docker seems to work as long as I use a user-created network with IPv6 strictly defined. The Docker default bridge also works if you specify the links inside of the docker-compose file, but that seems to be depricated so let's not waste too much time on that. For those looking for instructions on the Docker part I just followed the guide outlined here.
Now that everything is up and running it seems fine, but again if you are thinking of running an IPv6 only server infrastructure, set aside a lot of time for problem solving. Even simple applications like this require a lot of research to get up and running successfully with outbound network functioning and everything linked up in the correct way.