mirror of
https://github.com/rybbit-io/rybbit.git
synced 2025-05-11 12:25:36 +02:00
Add caddy (#90)
* Add Nginx and Certbot services to Docker Compose - Introduced Nginx service with custom configuration for handling HTTP and HTTPS traffic, including volume mounts for templates and entrypoint script. - Added Certbot service for automated SSL certificate management, with a renewal loop and environment variable support for domain and email. - Updated existing services to include restart policies and removed unnecessary port mappings for backend and client services. - Enhanced volume management by adding certbot-conf and certbot-www for certificate storage and challenge handling. * remove volume * Replace Nginx and Certbot with Caddy in Docker Compose - Removed Nginx and Certbot services, streamlining the configuration for SSL management. - Introduced Caddy service with automatic HTTPS support and simplified volume management. - Updated environment variables for domain and email configuration, ensuring compatibility with Caddy's setup. - Enhanced volume definitions for persistent data and configuration storage. * Fix * Fix * Remove Nginx and Certbot configurations from Docker setup - Deleted Nginx and Certbot Dockerfiles, entrypoint scripts, and associated configuration files to streamline the project. - Updated docker-compose.yml to remove Certbot email configuration, reflecting the transition to Caddy for SSL management. * Remove version declaration from docker-compose.yml to simplify configuration * Refactor login page to simplify account creation prompt - Removed conditional rendering for the sign-up link, ensuring it is always displayed for better user accessibility. * Update self-hosting documentation for Frogstats - Revamped the self-hosting guide to provide clearer instructions for setting up Frogstats. - Added prerequisites section detailing requirements such as a Linux VPS, domain name, Docker, and Git. - Enhanced setup steps with detailed commands for installing Docker and Git, cloning the repository, and running the setup script. - Included a callout for compatibility with Ubuntu 24 LTS and emphasized the importance of HTTPS for tracking scripts.
This commit is contained in:
parent
f890ec9b2b
commit
d10017686f
14 changed files with 178 additions and 122 deletions
24
Caddyfile
Normal file
24
Caddyfile
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Caddyfile
|
||||||
|
# Use the domain name passed from docker-compose environment
|
||||||
|
{$DOMAIN_NAME} {
|
||||||
|
# Enable compression
|
||||||
|
encode zstd gzip
|
||||||
|
|
||||||
|
# Proxy API requests to the backend service
|
||||||
|
handle_path /api/* {
|
||||||
|
reverse_proxy backend:3001
|
||||||
|
}
|
||||||
|
|
||||||
|
# Proxy all other requests to the client service
|
||||||
|
handle {
|
||||||
|
reverse_proxy client:3002
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional: Add security headers (example)
|
||||||
|
# header {
|
||||||
|
# Strict-Transport-Security max-age=31536000;
|
||||||
|
# X-Content-Type-Options nosniff
|
||||||
|
# X-Frame-Options DENY
|
||||||
|
# Referrer-Policy strict-origin-when-cross-origin
|
||||||
|
# }
|
||||||
|
}
|
|
@ -17,7 +17,6 @@ COPY . .
|
||||||
|
|
||||||
# Next.js collects completely anonymous telemetry data about general usage.
|
# Next.js collects completely anonymous telemetry data about general usage.
|
||||||
# Learn more here: https://nextjs.org/telemetry
|
# Learn more here: https://nextjs.org/telemetry
|
||||||
# Uncomment the following line in case you want to disable telemetry during the build.
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED 1
|
ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
ARG NEXT_PUBLIC_BACKEND_URL
|
ARG NEXT_PUBLIC_BACKEND_URL
|
||||||
ENV NEXT_PUBLIC_BACKEND_URL=${NEXT_PUBLIC_BACKEND_URL}
|
ENV NEXT_PUBLIC_BACKEND_URL=${NEXT_PUBLIC_BACKEND_URL}
|
||||||
|
|
|
@ -147,14 +147,12 @@ export default function Page() {
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{IS_CLOUD && (
|
<div className="text-center text-sm">
|
||||||
<div className="text-center text-sm">
|
Don't have an account?{" "}
|
||||||
Don't have an account?{" "}
|
<Link href="/signup" className="underline">
|
||||||
<Link href="/signup" className="underline">
|
Sign up
|
||||||
Sign up
|
</Link>
|
||||||
</Link>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
container_name: caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp" # Needed for HTTP/3
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile # Mount Caddy config file
|
||||||
|
- caddy_data:/data # Mount persistent data volume for certs etc.
|
||||||
|
- caddy_config:/config # Mount persistent config volume
|
||||||
|
environment:
|
||||||
|
# Pass domain name for use in Caddyfile
|
||||||
|
# Email is configured via Caddyfile global options
|
||||||
|
- DOMAIN_NAME=${DOMAIN_NAME}
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
- client
|
||||||
|
|
||||||
clickhouse:
|
clickhouse:
|
||||||
container_name: clickhouse
|
container_name: clickhouse
|
||||||
image: clickhouse/clickhouse-server:latest
|
image: clickhouse/clickhouse-server:latest
|
||||||
|
@ -19,6 +37,7 @@ services:
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
start_period: 10s
|
start_period: 10s
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:latest
|
image: postgres:latest
|
||||||
|
@ -27,18 +46,15 @@ services:
|
||||||
POSTGRES_USER: frog
|
POSTGRES_USER: frog
|
||||||
POSTGRES_PASSWORD: frog
|
POSTGRES_PASSWORD: frog
|
||||||
POSTGRES_DB: analytics
|
POSTGRES_DB: analytics
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
volumes:
|
volumes:
|
||||||
- postgres-data:/var/lib/postgresql/data
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
container_name: backend
|
container_name: backend
|
||||||
build:
|
build:
|
||||||
context: ./server
|
context: ./server
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
ports:
|
|
||||||
- "3001:3001"
|
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- CLICKHOUSE_HOST=http://clickhouse:8123
|
- CLICKHOUSE_HOST=http://clickhouse:8123
|
||||||
|
@ -59,6 +75,7 @@ services:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
client:
|
client:
|
||||||
container_name: client
|
container_name: client
|
||||||
|
@ -67,15 +84,16 @@ services:
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
args:
|
args:
|
||||||
NEXT_PUBLIC_BACKEND_URL: ${BASE_URL}
|
NEXT_PUBLIC_BACKEND_URL: ${BASE_URL}
|
||||||
ports:
|
|
||||||
- "3002:3002"
|
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- NEXT_PUBLIC_BACKEND_URL=${BASE_URL}
|
- NEXT_PUBLIC_BACKEND_URL=${BASE_URL}
|
||||||
- CLOUD=${CLOUD}
|
- CLOUD=${CLOUD}
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
clickhouse-data:
|
clickhouse-data:
|
||||||
postgres-data:
|
postgres-data:
|
||||||
|
caddy_data: # Persistent volume for Caddy's certificates and state
|
||||||
|
caddy_config: # Persistent volume for Caddy's configuration cache (optional but good practice)
|
||||||
|
|
|
@ -1,105 +1,68 @@
|
||||||
import { Steps } from 'nextra/components'
|
import { Steps } from 'nextra/components'
|
||||||
|
import { Callout } from 'nextra/components'
|
||||||
|
|
||||||
# Self Hosting
|
# Self Hosting Frogstats
|
||||||
|
|
||||||
You can self-host Frogstats by following the steps below.
|
This guide will walk you through setting up your own instance of Frogstats.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
## Create manually
|
Before you begin, ensure you have the following:
|
||||||
|
|
||||||
Nextra works like a Next.js plugin, and it accepts a theme config (layout) to
|
- **A Linux VPS:** We use [Hetzner Cloud](https://hetzner.cloud/?ref=QEdVqVpTLBDP) for everything (referral link - but Hetzner is legitimately the best value). CX11 for ~$4/month will be fine for small-medium sized projects.
|
||||||
render the page. To start: [^3]
|
- **A Domain Name:** You'll need a domain or subdomain (e.g., `tracking.yourdomain.com`) pointed to your VPS's IP address. HTTPS is required because browsers block tracking scripts served over insecure HTTP.
|
||||||
|
- **Docker Engine:** Docker is used to run the application stack. Installation instructions are in Step 1.
|
||||||
|
- **Git:** Needed to clone the repository.
|
||||||
|
|
||||||
|
<Callout type="info">
|
||||||
|
This guide has been tested on Ubuntu 24 LTS. While it should work on other distributions, your mileage may vary.
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
## Setup Steps
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
### Install Next.js, Nextra and React [^1]
|
### 1. Install Docker and Git
|
||||||
|
|
||||||
{/* ```sh npm2yarn
|
First, connect to your VPS via SSH.
|
||||||
npm i react react-dom next nextra
|
|
||||||
``` */}
|
|
||||||
|
|
||||||
### Install the docs theme [^2]
|
**Install Docker Engine:** Follow the official instructions for your Linux distribution:
|
||||||
|
[https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/)
|
||||||
|
|
||||||
```sh npm2yarn
|
Make sure to complete the [post-installation steps for Linux](https://docs.docker.com/engine/install/linux-postinstall/) as well, particularly adding your user to the `docker` group so you don't have to use `sudo` for every Docker command.
|
||||||
npm i nextra-theme-docs
|
|
||||||
|
**Install Git:** If Git is not already installed, install it using your distribution's package manager. For Debian/Ubuntu:
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt install -y git
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create the following Next.js config and theme config under the root directory
|
### 2. Clone the Frogstats Repository
|
||||||
|
|
||||||
```js filename="next.config.mjs"
|
Clone the project repository from GitHub:
|
||||||
import nextra from 'nextra'
|
```bash
|
||||||
|
git clone https://github.com/goldflag/frogstats.git
|
||||||
const withNextra = nextra({
|
cd frogstats
|
||||||
theme: 'nextra-theme-blog',
|
|
||||||
themeConfig: './theme.config.js'
|
|
||||||
})
|
|
||||||
export default withNextra()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create a `theme.config.js` file for the docs theme
|
### 3. Run the Setup Script
|
||||||
|
|
||||||
```js filename="theme.config.js"
|
The repository includes a setup script that configures the necessary environment variables (including generating a secure secret) and starts the application using Docker Compose.
|
||||||
export default {
|
|
||||||
project: {
|
Run the script, replacing `your.domain.name` with the domain or subdomain you configured in the prerequisites:
|
||||||
link: 'https://github.com/shuding/nextra' // GitHub link in the navbar
|
```bash
|
||||||
},
|
chmod +x setup.sh
|
||||||
docsRepositoryBase: 'https://github.com/shuding/nextra/blob/master', // base URL for the docs repository
|
./setup.sh your.domain.name
|
||||||
getNextSeoProps: () => ({ titleTemplate: '%s – Nextra' }),
|
|
||||||
navigation: true,
|
|
||||||
darkMode: true,
|
|
||||||
footer: {
|
|
||||||
text: `MIT ${new Date().getFullYear()} © Shu Ding.`
|
|
||||||
},
|
|
||||||
editLink: {
|
|
||||||
text: 'Edit this page on GitHub'
|
|
||||||
},
|
|
||||||
logo: (
|
|
||||||
<>
|
|
||||||
<svg>...</svg>
|
|
||||||
<span>Next.js Static Site Generator</span>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
head: (
|
|
||||||
<>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<meta name="description" content="Nextra: the next docs builder" />
|
|
||||||
<meta name="og:title" content="Nextra: the next docs builder" />
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
primaryHue: {
|
|
||||||
dark: 204,
|
|
||||||
light: 212
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!NOTE]
|
The script will create a `.env` file and then build and start the containers. This might take a few minutes the first time.
|
||||||
>
|
|
||||||
> More configuration options for the docs theme can be found
|
|
||||||
> [here](/themes/docs/configuration).
|
|
||||||
|
|
||||||
### You are good to go! Run `next dev` to start
|
### 4. Sign Up
|
||||||
|
|
||||||
|
Once the services are running, Caddy (the webserver) will automatically obtain an SSL certificate for your domain.
|
||||||
|
|
||||||
|
Open your browser and navigate to `https://your.domain.name/signup` (using the domain you provided to the setup script).
|
||||||
|
|
||||||
|
Create your admin account. You can then log in and start adding your websites!
|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
---
|
Congratulations! You have successfully self-hosted Frogstats.
|
||||||
|
|
||||||
<span id="sidebar-and-anchor-links" />
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
>
|
|
||||||
> Any `.md` or `.mdx` file will turn into a doc page and be displayed in
|
|
||||||
> sidebar. You can also create a `_meta.js` file to customize the page order and
|
|
||||||
> title. <br /> Check the source code: https://github.com/shuding/nextra for
|
|
||||||
> more information.
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
>
|
|
||||||
> You can also use
|
|
||||||
> [`<style jsx>`](https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js)
|
|
||||||
> to style elements inside `theme.config.js`.
|
|
||||||
|
|
||||||
[^1]: Install Next.js, Nextra and React.
|
|
||||||
|
|
||||||
[^2]: Install the docs theme.
|
|
||||||
|
|
||||||
[^3]: To start.
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Docker Compose already ensures services are ready using healthchecks
|
|
||||||
# and dependency conditions in the docker-compose.yml file
|
|
||||||
|
|
||||||
# Run migrations explicitly using the npm script
|
# Run migrations explicitly using the npm script
|
||||||
echo "Running database migrations...."
|
echo "Running database migrations...."
|
||||||
npm run db:push
|
npm run db:push
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { db } from "../../db/postgres/postgres.js";
|
||||||
import { member } from "../../db/postgres/schema.js";
|
import { member } from "../../db/postgres/schema.js";
|
||||||
import { getSitesUserHasAccessTo } from "../../lib/auth-utils.js";
|
import { getSitesUserHasAccessTo } from "../../lib/auth-utils.js";
|
||||||
import { getSubscriptionInner } from "../stripe/getSubscription.js";
|
import { getSubscriptionInner } from "../stripe/getSubscription.js";
|
||||||
|
import { IS_CLOUD } from "../../lib/const.js";
|
||||||
|
|
||||||
// Default event limit for users without an active subscription
|
// Default event limit for users without an active subscription
|
||||||
const DEFAULT_EVENT_LIMIT = 10_000;
|
const DEFAULT_EVENT_LIMIT = 10_000;
|
||||||
|
@ -13,12 +14,20 @@ export async function getSites(req: FastifyRequest, reply: FastifyReply) {
|
||||||
// Get sites the user has access to
|
// Get sites the user has access to
|
||||||
const sitesData = await getSitesUserHasAccessTo(req);
|
const sitesData = await getSitesUserHasAccessTo(req);
|
||||||
|
|
||||||
// Enhance sites data - removing usage limit information for now
|
|
||||||
const enhancedSitesData = await Promise.all(
|
const enhancedSitesData = await Promise.all(
|
||||||
sitesData.map(async (site) => {
|
sitesData.map(async (site) => {
|
||||||
let isOwner = false;
|
let isOwner = false;
|
||||||
let ownerId = "";
|
let ownerId = "";
|
||||||
|
|
||||||
|
if (!IS_CLOUD) {
|
||||||
|
return {
|
||||||
|
...site,
|
||||||
|
monthlyEventCount: 0,
|
||||||
|
eventLimit: Infinity,
|
||||||
|
overMonthlyLimit: false,
|
||||||
|
isOwner: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
// Determine ownership if organization ID exists
|
// Determine ownership if organization ID exists
|
||||||
if (site.organizationId) {
|
if (site.organizationId) {
|
||||||
const orgOwnerResult = await db
|
const orgOwnerResult = await db
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import { eq } from "drizzle-orm";
|
||||||
import { stripe } from "../../lib/stripe.js";
|
import { FastifyReply, FastifyRequest } from "fastify";
|
||||||
|
import Stripe from "stripe";
|
||||||
import { db } from "../../db/postgres/postgres.js";
|
import { db } from "../../db/postgres/postgres.js";
|
||||||
import { user as userSchema } from "../../db/postgres/schema.js";
|
import { user as userSchema } from "../../db/postgres/schema.js";
|
||||||
import { eq } from "drizzle-orm";
|
import { stripe } from "../../lib/stripe.js";
|
||||||
|
|
||||||
interface CheckoutRequestBody {
|
interface CheckoutRequestBody {
|
||||||
priceId: string;
|
priceId: string;
|
||||||
|
@ -49,7 +50,7 @@ export async function createCheckoutSession(
|
||||||
|
|
||||||
// 2. If the user doesn't have a Stripe Customer ID, create one
|
// 2. If the user doesn't have a Stripe Customer ID, create one
|
||||||
if (!stripeCustomerId) {
|
if (!stripeCustomerId) {
|
||||||
const customer = await stripe.customers.create({
|
const customer = await (stripe as Stripe).customers.create({
|
||||||
email: user.email,
|
email: user.email,
|
||||||
metadata: {
|
metadata: {
|
||||||
userId: user.id, // Link Stripe customer to your internal user ID
|
userId: user.id, // Link Stripe customer to your internal user ID
|
||||||
|
@ -65,7 +66,7 @@ export async function createCheckoutSession(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Create a Stripe Checkout Session
|
// 4. Create a Stripe Checkout Session
|
||||||
const session = await stripe.checkout.sessions.create({
|
const session = await (stripe as Stripe).checkout.sessions.create({
|
||||||
payment_method_types: ["card"],
|
payment_method_types: ["card"],
|
||||||
mode: "subscription",
|
mode: "subscription",
|
||||||
customer: stripeCustomerId,
|
customer: stripeCustomerId,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { stripe } from "../../lib/stripe.js";
|
||||||
import { db } from "../../db/postgres/postgres.js";
|
import { db } from "../../db/postgres/postgres.js";
|
||||||
import { user as userSchema } from "../../db/postgres/schema.js";
|
import { user as userSchema } from "../../db/postgres/schema.js";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
import Stripe from "stripe";
|
||||||
|
|
||||||
interface PortalRequestBody {
|
interface PortalRequestBody {
|
||||||
returnUrl: string;
|
returnUrl: string;
|
||||||
|
@ -44,7 +45,9 @@ export async function createPortalSession(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Create a Stripe Billing Portal Session
|
// 2. Create a Stripe Billing Portal Session
|
||||||
const portalSession = await stripe.billingPortal.sessions.create({
|
const portalSession = await (
|
||||||
|
stripe as Stripe
|
||||||
|
).billingPortal.sessions.create({
|
||||||
customer: user.stripeCustomerId,
|
customer: user.stripeCustomerId,
|
||||||
return_url: returnUrl, // The user will be redirected here after managing their billing
|
return_url: returnUrl, // The user will be redirected here after managing their billing
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,7 +34,7 @@ export async function getSubscriptionInner(userId: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. List active subscriptions for the customer from Stripe
|
// 2. List active subscriptions for the customer from Stripe
|
||||||
const subscriptions = await stripe.subscriptions.list({
|
const subscriptions = await (stripe as Stripe).subscriptions.list({
|
||||||
customer: user.stripeCustomerId,
|
customer: user.stripeCustomerId,
|
||||||
status: "active", // Only fetch active subscriptions
|
status: "active", // Only fetch active subscriptions
|
||||||
limit: 1, // Users should only have one active subscription in this model
|
limit: 1, // Users should only have one active subscription in this model
|
||||||
|
|
|
@ -29,7 +29,7 @@ export async function handleWebhook(
|
||||||
return reply.status(400).send("Webhook error: No raw body available");
|
return reply.status(400).send("Webhook error: No raw body available");
|
||||||
}
|
}
|
||||||
|
|
||||||
event = stripe.webhooks.constructEvent(
|
event = (stripe as Stripe).webhooks.constructEvent(
|
||||||
rawBody,
|
rawBody,
|
||||||
sig as string,
|
sig as string,
|
||||||
webhookSecret
|
webhookSecret
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { eq, inArray, and } from "drizzle-orm";
|
||||||
import { db } from "../db/postgres/postgres.js";
|
import { db } from "../db/postgres/postgres.js";
|
||||||
import { processResults } from "../api/analytics/utils.js";
|
import { processResults } from "../api/analytics/utils.js";
|
||||||
import { stripe } from "../lib/stripe.js";
|
import { stripe } from "../lib/stripe.js";
|
||||||
|
import Stripe from "stripe";
|
||||||
|
|
||||||
// Default event limit for users without an active subscription
|
// Default event limit for users without an active subscription
|
||||||
const DEFAULT_EVENT_LIMIT = 10_000;
|
const DEFAULT_EVENT_LIMIT = 10_000;
|
||||||
|
@ -69,7 +70,7 @@ async function getUserSubscriptionInfo(userData: {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch active subscriptions for the customer from Stripe
|
// Fetch active subscriptions for the customer from Stripe
|
||||||
const subscriptions = await stripe.subscriptions.list({
|
const subscriptions = await (stripe as Stripe).subscriptions.list({
|
||||||
customer: userData.stripeCustomerId,
|
customer: userData.stripeCustomerId,
|
||||||
status: "active",
|
status: "active",
|
||||||
limit: 1,
|
limit: 1,
|
||||||
|
|
|
@ -5,13 +5,8 @@ dotenv.config();
|
||||||
|
|
||||||
const secretKey = process.env.STRIPE_SECRET_KEY;
|
const secretKey = process.env.STRIPE_SECRET_KEY;
|
||||||
|
|
||||||
if (!secretKey) {
|
export const stripe = secretKey
|
||||||
throw new Error(
|
? new Stripe(secretKey, {
|
||||||
"Stripe secret key is not defined in environment variables. Please set STRIPE_SECRET_KEY."
|
typescript: true, // Enable TypeScript support
|
||||||
);
|
})
|
||||||
}
|
: null;
|
||||||
|
|
||||||
export const stripe = new Stripe(secretKey, {
|
|
||||||
// apiVersion: "2024-06-20", // Use the latest API version - Removed to use SDK default
|
|
||||||
typescript: true, // Enable TypeScript support
|
|
||||||
});
|
|
||||||
|
|
48
setup.sh
Normal file
48
setup.sh
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit immediately if a command exits with a non-zero status.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Check if domain name argument is provided
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Usage: $0 <domain_name>"
|
||||||
|
echo "Example: $0 myapp.example.com"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DOMAIN_NAME="$1"
|
||||||
|
BASE_URL="https://${DOMAIN_NAME}"
|
||||||
|
|
||||||
|
# Generate a secure random secret for BETTER_AUTH_SECRET
|
||||||
|
# Uses OpenSSL if available, otherwise falls back to /dev/urandom
|
||||||
|
if command -v openssl &> /dev/null; then
|
||||||
|
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
|
||||||
|
elif [ -e /dev/urandom ]; then
|
||||||
|
BETTER_AUTH_SECRET=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32)
|
||||||
|
else
|
||||||
|
echo "Error: Could not generate secure secret. Please install openssl or ensure /dev/urandom is available." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create or overwrite the .env file
|
||||||
|
echo "Creating .env file..."
|
||||||
|
cat > .env << EOL
|
||||||
|
# Variables configured by setup.sh
|
||||||
|
DOMAIN_NAME=${DOMAIN_NAME}
|
||||||
|
BASE_URL=${BASE_URL}
|
||||||
|
BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
||||||
|
|
||||||
|
# Defaulting to empty strings to suppress docker-compose warnings
|
||||||
|
STRIPE_SECRET_KEY=
|
||||||
|
STRIPE_WEBHOOK_SECRET=
|
||||||
|
CLOUD=
|
||||||
|
EOL
|
||||||
|
|
||||||
|
echo ".env file created successfully with domain ${DOMAIN_NAME}."
|
||||||
|
|
||||||
|
# Build and start the Docker Compose stack
|
||||||
|
echo "Building and starting Docker services..."
|
||||||
|
docker compose up --build -d
|
||||||
|
|
||||||
|
echo "Setup complete. Services are starting in the background."
|
||||||
|
echo "You can monitor logs with: docker compose logs -f"
|
Loading…
Add table
Add a link
Reference in a new issue