Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dockerize app #6

Merged
merged 2 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
IP2LOCATION_API_KEY=***********
COOKIE_SECRET=***********
FORM_SUBMISSION_ACTION_URL=***********
DB_PATH=*[OPTIONAL_CAN_BE_REMOVED]*
PORT=*[OPTIONAL_CAN_BE_REMOVED]*
HOST=*[OPTIONAL_CAN_BE_REMOVED]*
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
sqlite.db
node_modules/
dist/
data/*
!data/.gitkeep
.env
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.6.0
18.20.5
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM node:18-alpine3.20

WORKDIR /app
VOLUME data
EXPOSE 3000

COPY package.json package-lock.json tsconfig.json .nvmrc /app/
COPY src /app/src
COPY static /app/static

COPY .env /app

RUN npm ci
RUN echo "DB_PATH=./data/sqlite.db" >> /app/.env
RUN echo "PORT=3000" >> /app/.env
RUN echo "HOST=0.0.0.0" >> /app/.env

CMD ["npm", "run", "start:ci"]
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ You can run import script:

The file should include one domain per line. This script will ingest the domains and ignore any duplicates. This data is not part of this repository.

If you are running the application via docker, provide additional flag `--dbFilePath=./data/sqlite.db`, assuming you are running it in specified `WORKDIR`.

## Development

### JSON schema
Expand All @@ -48,6 +50,32 @@ Endpoints use JSON schema to define the constraints of inputs. Run `npm run sche

## Deployment

### Docker (recommended)

Make sure you have all your secrets define in `.env`, see `.env.example` to see what these are. The values for `HOST`, `PORT` and `DB_PATH` will be overwritten when the image is built.

If you have existing database, place it in this location: `./data/sqlite.db` (the name must stay the same), otherwise database will be created at that location.

Build the image:

```bash
$ docker build -t czdomains .
```

Run the container (recommended settings for server environment):

```bash
$ docker run -d --name czdomains -p 3000:3000 --restart always -v $(pwd)/data:/app/data czdomains
```

This will run the application in daemon mode (in the background) and make sure it is automatically restarted.
The volume `-v` flag is important so the database can be found at the right place and data is persisted.
You can customize the host port with `-p` flag if you need to, e.g. if you want to have it accessible on port 80, change it to `-p 80:3000`.

The application will automatically run all the migrations when it starts. If you need to import data, follow the instructions in the `Populating database with data` section.

### Bare metal

Make sure you have all your secrets define in `.env`, copy `.env.example` to see what these are.

Application can be started with `npm run start`. You should provide `PORT` environment variable to specify which port to run the webserver on. You can add this variable to `.env` file as well.
Expand Down
Empty file added data/.gitkeep
Empty file.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"scripts": {
"build": "tsc -p tsconfig.json",
"prebuild": "npm run clean",
"prestart:ci": "DB_PATH=$(node -e 'console.log(require(\"minidotenv\")()(\"DB_PATH\"))'); tsx src/migrate.ts --dbFilePath=$DB_PATH",
"start:ci": "NODE_ENV=production ts-node --transpile-only src/index.ts",
"start": "NODE_ENV=production ts-node --transpile-only src/index.ts",
"dev": "NODE_ENV=development ts-node-dev --respawn --transpile-only src/index.ts",
"dev:debug": "NODE_ENV=development ts-node-dev --inspect-brk --respawn --transpile-only src/index.ts",
Expand All @@ -24,7 +26,7 @@
"url": "git+https://github.com/comatory/czdomains.git"
},
"engines": {
"node": ">= 18.6.0"
"node": "18.20.5"
},
"keywords": [
"server",
Expand Down
8 changes: 7 additions & 1 deletion src/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ const cliOptions = yargs(process.argv.slice(2))
description: 'Path to file with domain names',
demandOption: true,
})
.options('dbFilePath', {
alias: 'db',
type: 'string',
description: 'Path to the sqlite database file',
demandOption: false,
})
.parseSync();

const HTTPS_RE = /^http(s?):\/\//i;
Expand Down Expand Up @@ -110,7 +116,7 @@ void (async ({ filePath }: typeof cliOptions) => {

console.info('Connecting to database...');

const dbPath = join(__dirname, '..', './sqlite.db');
const dbPath = join(__dirname, '..', cliOptions.dbFilePath ?? './sqlite.db');
const db = await open<sqlite3.Database, sqlite3.Statement>({
filename: dbPath,
driver: sqlite3.Database,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import { submitPlugin } from './routes/submit/routes';
/**
* Function that builds and runs the Fastify server.
*/
export async function createApp() {
const server = await configureServices(fastify());
export async function createApp(options: { dbFilePath: string | undefined }) {
const server = await configureServices(fastify(), options);

configureParsers(server);
configureHooks(server);
Expand Down
8 changes: 5 additions & 3 deletions src/lib/config/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { createDatabase } from '../services/db';
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
export type Services = UnwrapPromise<ReturnType<typeof createServices>>;

async function createServices() {
const db = await createDatabase();
async function createServices({ dbFilePath }: { dbFilePath?: string }) {
const db = await createDatabase({ dbFilePath });

return {
db,
Expand All @@ -15,8 +15,10 @@ async function createServices() {

export async function configureServices(
app: FastifyInstance,
options: { dbFilePath: string | undefined },
): Promise<FastifyInstance> {
const services = await createServices();
const { dbFilePath } = options;
const services = await createServices({ dbFilePath });

app.decorate('services', services);

Expand Down
7 changes: 5 additions & 2 deletions src/lib/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { createApp } from './app';
const PORT = Number.isNaN(Number(process.env.PORT))
? 3000
: Number(process.env.PORT);
const HOST = process.env.HOST;

const DB_FILE_PATH = process.env.DB_PATH ?? 'sqlite.db';

(async () => {
const app = await createApp();
const app = await createApp({ dbFilePath: DB_FILE_PATH });

app.listen({ port: PORT }, (err, address) => {
app.listen({ port: PORT, host: HOST }, (err, address) => {
if (err) {
console.error(err);
process.exit(1);
Expand Down
4 changes: 2 additions & 2 deletions src/lib/services/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { cwd } from 'node:process';
import { open } from 'sqlite';
import sqlite3 from 'sqlite3';

export async function createDatabase() {
export async function createDatabase({ dbFilePath }: { dbFilePath?: string }) {
const db = await open({
filename: join(cwd(), 'sqlite.db'),
filename: join(cwd(), dbFilePath ?? 'sqlite.db'),
driver: sqlite3.Database,
});

Expand Down
2 changes: 1 addition & 1 deletion src/lib/test-utils/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
export type TestApp = UnwrapPromise<ReturnType<typeof createApp>>;

export async function createTestApp(): Promise<TestApp> {
return await createApp();
return await createApp({ dbFilePath: undefined });
}
17 changes: 16 additions & 1 deletion src/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const cliOptions = yargs(process.argv.slice(2))
type: 'boolean',
description: 'List all migrations',
})
.options('dbFilePath', {
alias: 'db',
type: 'string',
description: 'Path to the sqlite database file',
require: false,
})
.help()
.parseSync();

Expand Down Expand Up @@ -64,7 +70,16 @@ async function migrate(client: Database, version?: string) {

void (async (options: typeof cliOptions) => {
verbose();
const client = new Database(join(__dirname, '..', 'sqlite.db'));

if (options.filePath) {
console.info(`Override detected. Using database file: ${options.filePath}`);
}

const dbPath = options.dbFilePath
? join(__dirname, '..', options.dbFilePath)
: join(__dirname, '..', 'sqlite.db');

const client = new Database(dbPath);

try {
if (options.list) {
Expand Down