April 19, 2025
At first glance, What is mean by wildcard domain? And what is it used for? Let’s understand it thoroughly.
Wildcard subdomains open up many interesting possibilities for building dynamic, user-centric web applications. Here are some project ideas that could leverage wildcard subdomains effectively:
Each user gets a blog at broisnees.yourblog.com Customizable themes and layouts per subdomain, you can take the example medium. You got what i mean, and you can also leverage wildcard subdomains to host your own domain. we will go through how can we actually use it.
In this blog, I have only used the single service but in your sceneriao you can also use the server, ( ngnix, caddy ) then locate to your different webapp.
Projects includes multiple tools and technologies.
Bun, elysia, neon serverless pg, drizzle, flyio, cloudflare, docker
Let’s create the project using the starting elysia command **bun create elysia
myapp**, after you initialized your project using elysia, you can run the project then it should run on port 3000.
For database
Today I am going to use the neon serverless postgres database
setup with drizzle orm, which is my favourite goto orm.
You can checkout the refrence repo of my Github.
inside of the src
folder you will find the index.ts
file which is the main
entrypoint file. before it, we are going to create the db
folder inside of the
src folder,
db/index.ts
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
import * as schema from './schema';
if (!process.env.DATABASE_URL) {
throw new Error('Database credentials missing.');
}
export const sql = neon(process.env.DRIZZLE_DATABASE_URL!);
const db = drizzle(sql, {
schema,
});
export { schema, db };
also you should create the drizzle.config.ts
in your root dir, if you are not
very familier with drizzle checkkout their
docs.
// /drizzle.config.ts
import type { Config } from 'drizzle-kit';
export default {
schema: './src/db/schema/index.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: String(process.env.DRIZZLE_DATABASE_URL),
},
verbose: true,
strict: true,
} satisfies Config;
Now we are going to create the db/schema/index.ts
file inside of the db
folder.
import { integer, pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
export const usersTable = pgTable('users_table', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
age: integer('age').notNull(),
email: text('email').notNull().unique(),
});
export const postsTable = pgTable('posts_table', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
content: text('content').notNull(),
userId: integer('user_id')
.notNull()
.references(() => usersTable.id, { onDelete: 'cascade' }),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at')
.notNull()
.$onUpdate(() => new Date()),
});
export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;
export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
Ok we are now finished with the databse files, one last thing is to modify the
main entrypoint file, src/index.ts
import swagger from '@elysiajs/swagger';
import { Elysia } from 'elysia';
import { db, schema } from './db';
import { eq } from 'drizzle-orm';
export function getCname<T extends Request>(req: T) {
return req.headers.get('host')?.split('.')[0];
}
const app = new Elysia()
.use(swagger())
.derive(({ request }) => {
return { cname: getCname(request) };
})
.get('/', async ({ cname }) => {
const user = await db.query.usersTable.findFirst({
where: eq(schema.usersTable.name, cname!),
});
if (!user) return `You do not have the access.`;
return `Hello, ${cname}`;
})
.listen(process.env.PORT!);
console.log(
`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`,
);
If you have noticed we have been using two environment which is port
and
DATABASE_URL
# .env
PORT=8080
DRIZZLE_DATABASE_URL="postgresql://yourvalidneonurl@ep-still-bush-a5e3y5t2.us-east-2.aws.neon.tech/neondb?sslmode=require"
You can find out the database url in the neon project dashboard.
We are done with setting up the code base. now we are going to deploy it.
If you don’t have fly cli installed in your pc, use brew install flyctl
to
install fly in your machine, or checkout fly.io for more
fly launch
When using this command if you are not authorized it will ask you to login, after login it will setup the configuration and as it detects the bun application it setups the fly.toml file.
It will generate the dockerfile for you, if not here is the simple dockerfile for bun
FROM oven/bun as base
LABEL fly_launch_runtime="Bun"
WORKDIR /app
ENV NODE_ENV="production"
# ENV DATABASE_URL=""
FROM base as build
RUN apt-get update -qq && \
apt-get install -y build-essential pkg-config python-is-python3
# Install node modules
COPY --link bun.lockb package.json ./
RUN bun install --ci
# Copy application code
COPY --link . .
FROM base
COPY --from=build /app /app
EXPOSE 8080
CMD [ "bun", "run", "dev" ] # Start the server by default
Also fly lauch
will create the fly.toml file in your root directory. which
looks like this
app = 'mydocsbackend'
primary_region = 'ams'
[build]
[env]
PORT = '8080'
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']
[[vm]]
memory = '512mb'
cpu_kind = 'shared'
cpus = 1
But before that we need to deploy the database, so we can use the deploy flag in the fly.toml to run the migrate command and deploy the database
[deploy]
release_command = "bun run migrate"
Here is the package.json script
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "bun run --watch src/index.ts",
"migrate": "npx drizzle-kit migrate",
"db:push": "bunx drizzle-kit push",
"generate": "bunx drizzle-kit generate"
}
"dependencies": {
"@elysiajs/swagger": "^1.1.0",
"@neondatabase/serverless": "^0.9.4",
"drizzle-orm": "^0.32.1",
"elysia": "latest",
}
you can use either db
or migrate, db will push the db server, now we are everything setup for deployment to fly io#deploy the application
fly deploy
After successful deployment you should see and fly.io gives the hostname for your application in my case it’s mydocsbackend.fly.dev and you can access your app
Go to your cloudflare account and click on DNS and then Add Record
So where did i get this ipv4
hostname from? It’s from fly.io, if you go to
fly.io in your app dashboard you will see certificates
you need to add new certificate pointing to your website here in my case it’s *.nischal-dahal.com.np, here I don’t have .com domain so i am using the country level domain.
You won’t be able to see the green dots in verified and rsa, ecdsa check at the first time, you need to add the _achme_challange CNAME find out in Domain ownership verification , pointing to the value that is given by fly.io, then after sometime it will be verified and ready to go.
if you had looked at the index.ts
in the src directory, you will see some
simple code, it’s just a simple api with bun, where i am getting name of user
from the user database from our neon db, and if found show the hello, message
else no authorized
Example
because test doesnot exists in our database.
I haven’t created the seed script, you can create or add the data on your user
table using drizzle-kit studio npx drizzle-kit studio
Add record manually, now let’s try out nees.localhost:8080
,
You can use the
subdomain
in localhost.
Now you can also check it on production, it should give you the same result. If
you haven’t deployed after changes, you can use fly deploy
We setup, deployed and tested our bun, elysia and drizzle projects on fly.io you can use other hosting platforms as well, like railway,coolify and many more
© 2025 - present @nischalxdahal | All Rights Reserved.