Combining fetch() and email() workers on CF Free

I have two functions Workers, one uses async fetch(request) and the other uses async email(message, env, ctx)

The docs say that I can combine these into a single worker by putting both within the export default { } function, but when I do that I don't see the worker listed under Email > Email Routing > Routing Rules > Edit > Destination.

Is there a trick to get it to show up here, or do I have to have 2 separate workers?

(The disadvantage to having two is I have an array that I have to copy from one to the other every time I add a domain, and it would be easier to just have to update it once)

reddit.com
u/csdude5 — 1 day ago

Worker to redirect emails to second domain

I have several domains that I want the emails to be redirected to matching emails on other domains. For example, I want info@foo.com to be delivered to info@bar.com .

The destination sites are hosting clients, and I don't have a real way to test it without waiting on them to reply. Sometimes that takes days!!

Do you see any problems with this worker, or is there a better way?

const DOMAIN_MAP = Object.freeze({
 'foo.com':   'https://www.bar.com',
 'lorem.com': 'https://ipsum.net/blah',
 // other domains
});

export default {
  async email(message, env, ctx) {
    const recipient = message.to.toLowerCase();

    // Split at the LAST @ just to be safe
    const at = recipient.lastIndexOf('@');

    if (at === -1) {
      message.setReject('Invalid recipient address.');
      return;
    }

    const localPart = recipient.substring(0, at);
    const sourceDomain = recipient.substring(at + 1);

    let destinationDomain = DOMAIN_MAP[sourceDomain];

    if (!destinationDomain) {
      message.setReject('This domain is not configured for email forwarding.');
      return;
    }

    destinationDomain = new URL(destinationDomain).hostname.replace(/^(https?:\/\/)?(www\.)?/, '')

    await message.forward(`${localPart}@${destinationDomain}`);
  },
};
u/csdude5 — 1 day ago

Subdomain throwing 522/526 error

I have a parent domain with 62 child domains (parked on top of the parent at the server). In CF I created an A record for the parent of proxy.parent.com, then changed the A records for each child to CNAMEs for root and www that point to proxy.parent.com

I also changed ww2.parent.com to a CNAME to proxy.parent.com

Then at the parent > SSL/TLS > Origin Server I created a certificate for parent.com, *.parent.com, expiring on Jan 10, 2041.

Then at the parent > SSL/TLS > Custom Hostnames, I set the Fallback Origin to www.parent.com and added each of the child domains to Custom Hostname. This includes ww2.parent.com and ww2.one_child.com (which is parked on top of ww2.parent.com).

Yesterday I began getting a 526 error, sometimes a 522 error. An openssl command on the server for ww2.one_child.com showed that the cert had expired at 11:22pm, while the cert for www.one\_child.com wouldn't expire until 2041. So the problem seemed to point to the Origin Server cert.

Looking at ww2.one_child.com under Custom Hostname, it showed that the cert expires 2026-09-27. So definitely not that.

I discovered that I had failed to create an _acme-challenge CNAME for ww2.parent.com and for ww2.one_child.com, so I added_acme-challenge.ww2.parent.com with a value of ww2.parent.com.<value shown in CF> and _acme-challenge.ww2.one_child.com with a value of ww2.one_child.com.<value shown in CF>

The Certificate status and Hostname status for both of the ww2 subdomains show Active, and ppenssl now shows that the cert expires in 2041.

But I'm still getting a 522 error in the browser, sometimes a 526.

Any suggestions on where I messed up?

** SOLVED **

I discovered that I had to create a separate Origin Certificate for the ww2.one_child.com at CF > one_child.com > SSL/TLS > Origin Server, then installed that in WHM > SSL/TLS > Install an SSL Certificate on a Domain. I'm not 100% sure whether the other changes listed above helped, though.

reddit.com
u/csdude5 — 3 days ago
▲ 15 r/mysql

More fun with moving MyISAM to InnoDB (just so you can laugh at my pain)

If there's anybody that will appreciate this drama, it's y'all!

Quick backstory, I build this database sometime around 2004. It was all MyISAM until I added a couple of InnoDB tables around 2018-19. Then in 2021 I had a MAJOR crash that was related to InnoDB, so I put it all back to MyISAM and had to set `innodb_force_recovery=5` to get it back online.

Now I'm setting up a new server, and I'm altering it all to InnoDB while holding my breath and praying.

So early this morning (1am-ish) I was working on a table and created a FULLTEXT index, which threw an error. I altered it to InnoDB again to make sure there were no errors, optimized, etc, before realizing that the default /tmp/ directory was too small. So I set a new `tmpdir` in my.cnf and the new index built.

But then I saw that the old MyISAM table had 507,000 rows, while the live one only had 467,000! Somehow I'd lost 40,000 rows :-O

I went through EVERYTHING, even down to restoring full database backups. Nope, still missing.

THREE HOURS of late-night panic coding until it hits me... in phpMyAdmin, that `Showing rows 0 - 24 (467000 total...)` isn't accurate in InnoDB! So I do a simple `SELECT *...`, and... yep, it's all good. Same number of rows after all.

So there I am, almost 5am, heart racing, and it turns out that it was right all along.

reddit.com
u/csdude5 — 4 days ago

Using APCu or sessions to reduce MySQL queries

I have a lot of data stored in MySQL, and the values are used on every pageview. 15+ years ago, I set up sessions to reduce the queries. It's set up so that if a required session variable exists then it skips the query, but if it doesn't exist then it queries, sets the results to session variables, then maps those sessions to variables.

It looks like this:

if (session_id() === '') session_start();
 $sess_file = '/tmp/sess_' . session_id();
 if (is_file($sess_file)) chmod($sess_file, 0644);

if (!isset($_SESSION['siteID']))) {
 for ($attempt=0; $attempt < 3; $attempt++) {
  if ($attempt == 2) {
   // log error and return error page, whatever they're doing isn't working
  }

  $var_query = sprintf("SELECT * FROM vars WHERE foo='%s' LIMIT 1",
   mysqli_real_escape_string($dbh, $foo));

  $sth_vars = mysqli_query($dbh, $var_query);

  if (isset($sth_vars) && mysqli_num_rows($sth_vars)) {
   list($_SESSION['siteID'], $_SESSION['lorem'], $_SESSION['ipsum']) =
    mysql_fetch_row($sth_vars);

   $attempt = 3;
  }

  // Lookup failed, send alert and try again
  else {
   if ($attempt < 2) sleep(1);
   else exit;
  }
 }
}

session_commit();

// Map $_SESSION to variables 
foreach ($_SESSION as $session_key => $session_value) $$session_key = $session_value;

I'm setting up a new server, though, and have APCu installed.

Would APCu be a better option for this use than sessions?

reddit.com
u/csdude5 — 6 days ago
▲ 0 r/mysql

Foreign keys, yay or nay?

By today's standards, is there a value to using foreign keys beyond a safety net against developer error?

I have over 100 tables, and every site feature relies on joining 2 or more tables and matching up IDs. I'm debating on whether there's any benefit to creating foreign keys when the scripts are already developed and the only person that can ever touch them is me.

* CLARIFICATION: the only person that can touch the code and backend is me.

reddit.com
u/csdude5 — 6 days ago
▲ 7 r/cpanel

Potential bug with Transfer Tool on v136.0.33

This is more for people that have the same problem I had, hoping they can find this instead of spending hours panicking like I did.

I have a new VPS, using AlmaLinux v9.8.0 STANDARD kvm, cPanel Version 136.0.33.

I began to transfer a Wordpress site, but wasn't sure if it would work with the new version of PHP so I wanted to test run first. I used Transfer Tool, then de-selected:

Update DNS Zone 
Enable this setting to update DNS records on the destination server.

After the transfer I checked the DNS records on the old VPS and confirmed that they did not change.

Shortly thereafter, though, I discovered that an email sent to the client was rejected, and the bounce message noted that their email server was on the new VPS instead of the old one.

Then I looked at the live site and found that it was pointing to the new VPS!

It took about 3 hours to find that Transfer Tool modified the source VPS, anyway:

  1. a ProxyPass record was added to httpd.conf (with a dash-delimited version of the IP, so a simple grep for the new IP didn't find it; eg, http://123-45-67-89); and

  2. when I ran # exim -bt client@example.com (using the client's email address that had bounced), it returned the new VPS instead of the correct one: host new.vps.com [123.45.67.89]

The solutions were to run this to fix it in Apache:

whmapi1 unset_all_service_proxy_backends username=<account name>

then rebuild and restart Apache. Then run this for Exim (no restart required):

whmapi1 unset_manual_mx_redirects domain='<domain name for the account>'

I ran the one for Exim first before finding the problem in Apache, so running the first one MIGHT have fixed Exim, too.

This might be a feature instead of a bug, but I expected that when I disabled "Update DNS Zone" then it wouldn't change ANYTHING on the source VPS. I was wrong.

reddit.com
u/csdude5 — 10 days ago
▲ 2 r/mysql

When to use InnoDB vs MyISAM (or other)

In the beginning, I understood that InnoDB should be used on tables with a high number of inserts and relatively fewer selects.

Now Claude is telling me that this is essentially backwards.

And Google AI is telling me that MyISAM is more or less legacy and that pretty much EVERYTHING should be InnoDB now. The only exception (according to Google AI) is when you need to use COUNT(*) with no WHERE, in which case MyISAM is faster.

So what's the rule these days?

reddit.com
u/csdude5 — 11 days ago

Accommodating a custom WP theme built on PHP 7.4

I run a small hosting company, and have little to no experience with Wordpress myself. It's just something I offer clients.

I have one client that had a WP site built on a custom theme, using WP version 4.7.29. They also have these plugins:

Advanced Custom Fields 4.4.5
Contact Form 7 3.8.1
Document Gallery 2.3.7
Google Analytics for WordPress 4.3.5
NextScripts: Social Networks Auto-Poster 3.7.15
SSL Insecure Content Fixer 2.5.0
WP Realtime Sitemap 1.5.4
WordPress Importer 0.6.1

I'm removing the server that they're on, so I need to move them to a new one with PHP 8.4. I'm assuming that I'll have to install WP 7.0.2, too.

I CAN pay a monthly fee to install PHP 7.4 again, but is there a way to install the old WP version, too?

If not, any guesses on whether the old site will work properly with the updated software? How can I know other than "try it and see" (and risk breaking everything)?

reddit.com
u/csdude5 — 14 days ago

Is XM owned by MAGA or have right wing bias?

I use the XM app in my house and create artist stations to listen to while working. But for the last several weeks, no matter what station I create it overwhelmingly turns in to right-wing country music!

Eminem Radio - one Eminem song followed by 3-4 MAGA country songs

Dre Radio - same

Poison Radio - same

Today I created Afroman Radio - same.

Down voting songs has no impact, the same song will play again within the hour.

The only reason I can think of is a political bias, like what we see with TikTok. There's just no way that any algorithm would think that I want to hear "Am I the Only One" (Aaron Lewis), or Morgan Wallen, when I've chosen Eminem Radio.

reddit.com
u/csdude5 — 15 days ago

Is there a backend bias with XM?

Serious question here. I use the XM app in my house and create artist stations to listen to while working. But for the last several weeks, no matter what station I create it overwhelmingly turns in to right-wing country music!

Eminem Radio - one Eminem song followed by 3-4 MAGA country songs

Dre Radio - same

Poison Radio - same

Today I created Afroman Radio - same.

Down voting songs has no impact, the same song will play again within the hour.

The only reason I can think of is a political bias, like what we see with TikTok. There's just no way that any algorithm would think that I want to hear "Am I the Only One" (Aaron Lewis), or Morgan Wallen, when I've chosen Eminem Radio.

reddit.com
u/csdude5 — 15 days ago
▲ 14 r/Skunks

Cute lil stinker made a new home under my greenhouse!

First things first, I'm a huge animal lover and I've built my 5 acres of property around being friendly to wildlife and insects. I have about 3/4 acre cleared in the middle of the property with my house, and I'm surrounded by wild woods.

I have a greenhouse that I built on a wooden deck that is just barely off the ground. I've recently heard shuffling under the deck, but stomping around and making noise didn't seem to do anything.

Last week I saw this skunk for the first time (actually very friendly, there's a story there), and then a couple of days ago I saw it's big ol' fuzzy butt sticking out from under that greenhouse deck! So now I know, that's the shuffling noise I'd heard.

Considering the time of year (in western NC USA, zone 7A), I wouldn't be at all surprised to find out that this is a lady that had babies under there, and that they'll come out any day now.

I don't want to tame them or get them too use to humans, everybody else in this area will happily kill them :'-( But if there's gonna be here...

  1. should I get some dewormer and maybe some oral vaccines? I obviously can't give it to them directly, but I don't really want worms, fleas, etc being passed around my property either.

  2. should I toss some dry cat food or something on the ground nearby for them to find, so they're not hungry enough to eat my plants?

reddit.com
u/csdude5 — 17 days ago

That lil stinker!

I knew it was gonna happen! A few days ago I heard some rustling under the deck I built for the greenhouse, then today I saw that big black and white butt going under.

Considering that it's pretty much August, there's probably little pole kittens under there, too.

I'll post pics if I can take them!

From a distance... LOL

reddit.com
u/csdude5 — 19 days ago

Ohh, that pesky headliner

Just spent $4k on fixing the oil leak, harmonizer pulley, and locks. Got it back from the dealership, and now the headliner is falling down!!

It's not long for this world, I see it hanging on both rear corners, the front driver's corner (held up by the sun visor), and sagging all along the passenger side.

My options appear to be another $1,000 to have the dealership replace it (assuming they can actually get a new one), or take it out myself and reuse the board to cover with a new cloth (cloth and foam are about $150 on eBay). Which is gonna be way more work than I really have time to do.

Any other suggestions?

I don't suppose there's a well known reputable place that has a bunch of good condition parts I could check out?

reddit.com
u/csdude5 — 19 days ago

New battery is dead and won't charge, dead battery or is it the charger?

I have a 2012 Fisker Karma. It's a somewhat unique early plug-in hybrid, so it has a 4 cylinder GM engine that's really just a generator for the batteries.

It's been giving me some attitude lately, and step 1 was to replace the 12V battery.

(That's a hard job, you have to take off the front passenger side wheel and part of the wheel well to get to the battery, and then you can barely reach it)

Replacing it didn't solve all of the problems, and it appears I have a contactor that's frozen closed. So as a punishment I let it sit and think about what it's done for a few weeks.

Yesterday I found that the new 12V was dead, and it measures at 3.6V.

I connected a Battery Tender Junior to it to charge at the fuse block under the hood (the normal jump points), but it's flashing red and doesn't seem to recognize the battery at all! The charger says that it requires a minimum of 3V, so 3.6 should be enough.

What do you think, is the new battery dead or shorted, or is the charger just not working? Or does it simply not work at the jump points, even though other chargers have worked there in the past?

reddit.com
u/csdude5 — 20 days ago

Will damaged fins recover?

This guy is in my pond. I don't know when it happened, but it looks like bites were taken from his dorsal fin and tail!

He swims around just fine and is eating so I don't think he's in danger.

Will these grow back? Anything that I should be doing to help?

u/csdude5 — 22 days ago
▲ 11 r/webdev

Which site analytics is the most reliable?

I'm seeing pretty big discrepancies in analytics reports from different sources. I store the value locally to show my site users, so I'm looking for the most honest number.

Yesterday, my ad network shows that one of my sites had 33,941 pageviews. Since that's the money, I would think that they would be close to accurate.

A local count (incrementing a value in MySQL on each pageview, running through JavaScript to block most bots) shows 38,604.

Google Analytics shows 17,647, almost half of what the ad network showed.

And Cloudflare Web Analytics shows 22,190! 35% less than the ad network, but 25% higher than Analytics.

Which is the most honest? Or is there a better choice altogether?

reddit.com
u/csdude5 — 27 days ago

Reliability of CF Web Analytics

I'm seeing pretty big discrepancies in analytics reports from different sources. I store the value locally to show my site users, so I'm looking for the most honest number.

Yesterday, my ad network shows that one of my sites had 33,941 pageviews. Since that's the money, I would think that they would be close to accurate.

Google Analytics shows 17,647, almost half of what the ad network showed.

And Cloudflare Web Analytics shows 22,190! 35% less than the ad network, but 25% higher than Analytics.

Claude thinks that Google Analytics should be ignored entirely, and that CF is the most reliable. And it says that the difference between CF and the ad network comes down to "sampleInterval".

I built an API to get numbers straight from the logs:

query ($zoneTag: String!, $host: String!, $since: Time!, $until: Time!) {
    viewer {
        zones(filter: { zoneTag: $zoneTag }) {
            httpRequestsAdaptiveGroups(
                filter: {
                    datetime_geq: $since
                    datetime_lt: $until
                    clientRequestHTTPHost: $host
                    requestSource: "eyeball"
                }
                limit: 1000
                orderBy: [datetimeHour_ASC]
            ) {
                avg        { sampleInterval }
                sum        { visits }
            }
        }
    }
}

Claude AI says that sum { visits} is a sample, not raw, so to get the raw number I should multiply sum { visits } by avg { sampleInterval }

It also says that requestSource: "eyeball" eliminates likely bots, so is a more reliable count of real user traffic.

So my results:

# Using eyeball and multiplying by sampleInterval
27,645

# Not using eyeball and multiplying by sampleInterval
36,803

# Using eyeballs and not multiplying by sampleInterval
20,086

# Not using eyeball and not multiplying by sampleInterval
26,640

None of those match CF Web Analytics (22,190), though.

So which should I trust?

reddit.com
u/csdude5 — 27 days ago

Analytics via API for parked / proxied sites

I have a primary domain with 62 domains parked on top of it and proxied to the primary domain via CF. And now I'm trying to get the analytics data via API for each of those parked domains.

I built the below, but it only shows stats for the primary domain and not broken down for the parked ones.

How do I get the stats for each of the parked domains?

const TOKEN = 'XXXX';

$yesterday  = date('Y-m-d', strtotime('-1 day'));
$today      = date('Y-m-d');

$zones      = [];

$page       =
$totalPages = 1;

$zoneTag    =
$site       =
$date       =
$pageviews  =
$uniques    = null;

$graphqlQuery = <<<'EOL'
query ($zoneTag: String!, $since: String!, $until: String!) {
    viewer {
        zones(filter: { zoneTag: $zoneTag }) {
            httpRequests1dGroups(
                filter: { date_geq: $since, date_lt: $until }
                limit: 1
                orderBy: [date_ASC]
            ) {
                dimensions { date }
                sum { pageViews requests }
                uniq { uniques }
            }
        }
    }
}
EOL;

while ($page <= $totalPages) {
    $ch = curl_init("https://api.cloudflare.com/client/v4/zones?per_page=50&page=$page");
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER         => ["Authorization: Bearer " . TOKEN],
        CURLOPT_RETURNTRANSFER     => true,
    ]);

    $zonesResponse = json_decode(curl_exec($ch), true);
    curl_close($ch);

    foreach ($zonesResponse['result'] as $zone) {
        $payload = json_encode([
            'query'     => $graphqlQuery,
            'variables' => [
                'zoneTag' => $zone['id'],
                'since'   => $yesterday,
                'until'   => $today,
            ],
        ]);

        $ch = curl_init('https://api.cloudflare.com/client/v4/graphql');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_HTTPHEADER     => [
                "Authorization: Bearer " . TOKEN,
                'Content-Type: application/json'
            ],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 15,
        ]);

        $response = curl_exec($ch);
        $err      = curl_error($ch);
        curl_close($ch);

        if ($err) {
            error_log('CF stats error ' . $zone['id'] . ': ' . $err);
            continue;
        }

        $data = json_decode($response, true);
        $row  = $data['data']['viewer']['zones'][0]['httpRequests1dGroups'][0] ?? null;

        if (!$row) {
            error_log('CF stats: no data for ' . $zone['id'] . ' — ' . $response);
            continue;
        }

        $zoneTag   = $zone['id'];
        $site      = $zone['name'];
        $date      = $row['dimensions']['date'];
        $pageviews = (int) $row['sum']['pageViews'];
        $uniques   = (int) $row['uniq']['uniques'];

        echo <<<EOF
$site
$date
$pageviews
$uniques


EOF;

        usleep(300000);
    }

    $totalPages = ceil($zonesResponse['result_info']['total_count'] / $zonesResponse['result_info']['per_page']);
    $page++;
}
reddit.com
u/csdude5 — 27 days ago
▲ 71 r/turtles

Feeding a wild snapping turtle

This guy has been coming to my goldfish pond for several years, where he usually goes under the muck and I never see him again.

But this year I put in a bog filter that REALLY cleaned things up, and now I can see that he's feasting on the TetraPond Pond Sticks that I feed the fish! Now that he can see me, too, he literally comes right up to me like I'm his best friend.

Are the TetraPond Pond Sticks good for him, or should I get him something different?

(Note that I'm 60% sure it's a "he" based almost entirely on the size of the tail. I've never seen another one in the area and have never seen eggs)

u/csdude5 — 1 month ago