Skip to content

Commit

Permalink
improve(self-hosting): add resend and send email questions
Browse files Browse the repository at this point in the history
  • Loading branch information
lindesvard committed Feb 17, 2025
1 parent acc675b commit 7182ca6
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 27 deletions.
2 changes: 2 additions & 0 deletions apps/public/content/docs/self-hosting/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ If you upgrading from a previous version, you'll need to edit your `.env` file i

- `ALLOW_REGISTRATION` - If set to `false` new users will not be able to register (only the first user can register).
- `ALLOW_INVITATION` - If set to `false` new users will not be able to be invited.
- `RESEND_API_KEY` - If set, we'll use Resend to send e-mails.
- `EMAIL_SENDER` - The e-mail address that will be used to send e-mails.

## 0.0.6

Expand Down
3 changes: 2 additions & 1 deletion self-hosting/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ DATABASE_URL_DIRECT="$DATABASE_URL_DIRECT"
NEXT_PUBLIC_DASHBOARD_URL="$NEXT_PUBLIC_DASHBOARD_URL"
NEXT_PUBLIC_API_URL="$NEXT_PUBLIC_API_URL"
COOKIE_SECRET="$COOKIE_SECRET"
[email protected]
EMAIL_SENDER="$EMAIL_SENDER"
RESEND_API_KEY="$RESEND_API_KEY"
102 changes: 76 additions & 26 deletions self-hosting/quiz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ import bcrypt from 'bcrypt';
import inquirer from 'inquirer';
import yaml from 'js-yaml';

let envs = {
CLICKHOUSE_URL: '',
REDIS_URL: '',
DATABASE_URL: '',
DOMAIN_NAME: '',
COOKIE_SECRET: generatePassword(32),
RESEND_API_KEY: '',
EMAIL_SENDER: '',
};

type EnvVars = typeof envs;

const addEnvs = (env: Partial<EnvVars>) => {
envs = {
...envs,
...env,
};
};

function generatePassword(length: number) {
const charset =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
Expand Down Expand Up @@ -111,13 +130,7 @@ function removeServiceFromDockerCompose(serviceName: string) {
fs.writeFileSync(dockerComposePath, newYaml);
}

function writeEnvFile(envs: {
CLICKHOUSE_URL: string;
REDIS_URL: string;
DATABASE_URL: string;
DOMAIN_NAME: string;
COOKIE_SECRET: string;
}) {
function writeEnvFile(envs: EnvVars) {
const envTemplatePath = path.resolve(__dirname, '.env.template');
const envPath = path.resolve(__dirname, '.env');
const envTemplate = fs.readFileSync(envTemplatePath, 'utf-8');
Expand All @@ -132,7 +145,9 @@ function writeEnvFile(envs: {
.replace(
'$NEXT_PUBLIC_API_URL',
`${stripTrailingSlash(envs.DOMAIN_NAME)}/api`,
);
)
.replace('$RESEND_API_KEY', envs.RESEND_API_KEY)
.replace('$EMAIL_SENDER', envs.EMAIL_SENDER);

fs.writeFileSync(
envPath,
Expand Down Expand Up @@ -175,10 +190,10 @@ async function initiateOnboarding() {

// Domain name

const domainNameResponse = await inquirer.prompt([
const domain = await inquirer.prompt([
{
type: 'input',
name: 'domainName',
name: 'DOMAIN_NAME',
message: "What's the domain name you want to use?",
default: process.env.DEBUG ? 'http://localhost' : undefined,
prefix: '🌐',
Expand All @@ -192,6 +207,8 @@ async function initiateOnboarding() {
},
]);

addEnvs(domain);

// Dependencies

const dependenciesResponse = await inquirer.prompt([
Expand All @@ -205,7 +222,6 @@ async function initiateOnboarding() {
},
]);

let envs: Record<string, string> = {};
if (!dependenciesResponse.dependencies.includes('Clickhouse')) {
const clickhouseResponse = await inquirer.prompt([
{
Expand All @@ -217,10 +233,7 @@ async function initiateOnboarding() {
},
]);

envs = {
...envs,
...clickhouseResponse,
};
addEnvs(clickhouseResponse);
}

if (!dependenciesResponse.dependencies.includes('Redis')) {
Expand All @@ -232,10 +245,8 @@ async function initiateOnboarding() {
default: process.env.DEBUG ? 'redis://op-kv:6379' : undefined,
},
]);
envs = {
...envs,
...redisResponse,
};

addEnvs(redisResponse);
}

if (!dependenciesResponse.dependencies.includes('Postgres')) {
Expand All @@ -250,10 +261,8 @@ async function initiateOnboarding() {
: undefined,
},
]);
envs = {
...envs,
...dbResponse,
};

addEnvs(dbResponse);
}

// Proxy
Expand Down Expand Up @@ -293,6 +302,45 @@ async function initiateOnboarding() {
},
]);

const resend = await inquirer.prompt<{
RESEND_API_KEY: string;
}>([
{
type: 'input',
name: 'RESEND_API_KEY',
message: 'Enter your Resend API key (optional):',
},
]);

if (resend.RESEND_API_KEY) {
const emailSender = await inquirer.prompt<{
email: string;
}>([
{
type: 'input',
name: 'EMAIL_SENDER',
default: `no-reply@${envs.DOMAIN_NAME.replace(/https?:\/\//, '')}`,
message: 'The email which will be used to send out emails:',
validate: (value) => {
if (!value) {
return 'Field is required';
}

if (!value.includes('@')) {
return 'Please enter a valid email';
}

return true;
},
},
]);

addEnvs({
...resend,
...emailSender,
});
}

const basicAuth = await inquirer.prompt<{
password: string;
}>([
Expand Down Expand Up @@ -324,8 +372,10 @@ async function initiateOnboarding() {
DATABASE_URL:
envs.DATABASE_URL ||
'postgresql://postgres:postgres@op-db:5432/postgres?schema=public',
DOMAIN_NAME: domainNameResponse.domainName,
COOKIE_SECRET: generatePassword(32),
DOMAIN_NAME: envs.DOMAIN_NAME,
COOKIE_SECRET: envs.COOKIE_SECRET,
RESEND_API_KEY: envs.RESEND_API_KEY || '',
EMAIL_SENDER: envs.EMAIL_SENDER || '',
});

console.log('Updating docker-compose.yml file...\n');
Expand All @@ -350,7 +400,7 @@ async function initiateOnboarding() {
if (proxyResponse.proxy === 'Bring my own') {
removeServiceFromDockerCompose('op-proxy');
} else {
writeCaddyfile(domainNameResponse.domainName, basicAuth.password);
writeCaddyfile(envs.DOMAIN_NAME, basicAuth.password);
}

searchAndReplaceDockerCompose([['$OP_WORKER_REPLICAS', cpus.CPUS]]);
Expand Down

0 comments on commit 7182ca6

Please sign in to comment.