197 lines
7.7 KiB
Makefile
197 lines
7.7 KiB
Makefile
PROJECT_ROOT := $(abspath $(CURDIR)/..)
|
|
ENV_FILE := .env
|
|
COMPOSE_FILE := docker-compose.yml
|
|
COMPOSE_PROJECT := $(shell python3 $(CURDIR)/compose_name.py $(PROJECT_ROOT))
|
|
DOCKER_COMPOSE_BIN := $(shell docker compose version >/dev/null 2>&1 && printf 'docker compose' || { docker-compose --version >/dev/null 2>&1 && printf 'docker-compose'; })
|
|
|
|
ifeq ($(strip $(DOCKER_COMPOSE_BIN)),)
|
|
$(error docker compose (v2) or docker-compose is required)
|
|
endif
|
|
|
|
COMPOSE := $(DOCKER_COMPOSE_BIN) --env-file $(ENV_FILE) -p $(COMPOSE_PROJECT) -f $(COMPOSE_FILE)
|
|
CONTAINER_NAME = $(COMPOSE_PROJECT)-$(SERVICE)-1
|
|
ENV_REQUIRED := TELEGRAM_API_KEY CLIENT_TELEGRAM_API_KEY POSTGRES_DB POSTGRES_USER POSTGRES_PASSWORD DATABASE_URL SANIC_PORT BACKEND_HTTP_PORT
|
|
|
|
# Derive external domain and ports from .env for nginx/bootstrap helpers.
|
|
# PUBLIC_HOST may look like "https://my-public-node-103.projscale.dev" or have whitespace.
|
|
DOMAIN_FROM_ENV := $(shell awk -F= '$$1=="PUBLIC_HOST"{print $$2}' $(ENV_FILE) 2>/dev/null | tail -n1 | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$$//; s#^https?://##; s#/.*$$##')
|
|
DOMAIN ?= $(DOMAIN_FROM_ENV)
|
|
BACKEND_HTTP_PORT ?= $(shell awk -F= '$$1=="BACKEND_HTTP_PORT"{print $$2}' $(ENV_FILE) 2>/dev/null | tail -n1)
|
|
FRONTEND_HTTP_PORT ?= $(shell awk -F= '$$1=="FRONTEND_HTTP_PORT"{print $$2}' $(ENV_FILE) 2>/dev/null | tail -n1)
|
|
TUSD_HTTP_PORT ?= $(shell awk -F= '$$1=="TUSD_HTTP_PORT"{print $$2}' $(ENV_FILE) 2>/dev/null | tail -n1)
|
|
|
|
.PHONY: help bootstrap start up down stop restart build ps status logs logs-% tail tail-% shell shell-% env-check reset-config clean clean-images destroy nuke prune data-paths setup-nginx
|
|
|
|
help:
|
|
@echo "Available targets:"
|
|
@echo " make bootstrap # interactive setup + rebuild stack"
|
|
@echo " make up # start or recreate services"
|
|
@echo " make down # stop services (keep data)"
|
|
@echo " make restart # restart services"
|
|
@echo " make ps # show compose status"
|
|
@echo " make logs # follow logs (SERVICE=name to filter)"
|
|
@echo " make logs-backend-app # follow logs for backend"
|
|
@echo " make shell SERVICE=x # open bash inside service"
|
|
@echo " make clean # remove containers, keep data"
|
|
@echo " make destroy CONFIRM=1# nuke containers + volumes + data"
|
|
@echo " make reset-config # remove .env/.bak and swarm key"
|
|
@echo " make setup-nginx # install nginx vhost for PUBLIC_HOST (DOMAIN=override) and optionally run certbot"
|
|
@echo " make env-check # validate critical .env entries"
|
|
|
|
bootstrap start:
|
|
./start.sh
|
|
|
|
up:
|
|
$(COMPOSE) up -d --build
|
|
|
|
build:
|
|
$(COMPOSE) build
|
|
|
|
down stop:
|
|
$(COMPOSE) down --remove-orphans
|
|
|
|
restart:
|
|
$(COMPOSE) down --remove-orphans
|
|
$(COMPOSE) up -d --build
|
|
|
|
ps status:
|
|
$(COMPOSE) ps
|
|
|
|
logs:
|
|
$(COMPOSE) logs -f --since 1h $(SERVICE)
|
|
|
|
logs-%:
|
|
$(MAKE) logs SERVICE=$*
|
|
|
|
tail:
|
|
$(COMPOSE) logs -f --since 1h $(SERVICE)
|
|
|
|
tail-%:
|
|
$(MAKE) tail SERVICE=$*
|
|
|
|
shell:
|
|
@if [ -z "$(SERVICE)" ]; then \
|
|
echo "Specify SERVICE=backend-app (or another service)" >&2; \
|
|
exit 1; \
|
|
fi
|
|
@docker exec -it $(CONTAINER_NAME) /bin/bash
|
|
|
|
shell-%:
|
|
$(MAKE) shell SERVICE=$*
|
|
|
|
env-check:
|
|
@missing=0; \
|
|
for key in $(ENV_REQUIRED); do \
|
|
if ! grep -qE "^$${key}=" $(ENV_FILE); then \
|
|
echo "[missing] $$key"; \
|
|
missing=1; \
|
|
else \
|
|
val=$$(awk -F'=' -v k=$$key '$$1==k{print substr($$0,index($$0,$$2))}' $(ENV_FILE)); \
|
|
if [ -z "$$val" ]; then \
|
|
echo "[empty] $$key"; \
|
|
missing=1; \
|
|
fi; \
|
|
fi; \
|
|
done; \
|
|
if [ $$missing -ne 0 ]; then \
|
|
echo "Environment file incomplete" >&2; \
|
|
exit 1; \
|
|
fi
|
|
|
|
|
|
reset-config:
|
|
rm -f $(ENV_FILE) $(ENV_FILE).bak
|
|
rm -f ipfs/swarm.key
|
|
@echo "Configuration artifacts removed. Next run make bootstrap."
|
|
|
|
clean:
|
|
$(COMPOSE) down --remove-orphans
|
|
|
|
clean-images:
|
|
$(COMPOSE) down --remove-orphans --rmi local
|
|
|
|
prune:
|
|
$(COMPOSE) down --remove-orphans --volumes
|
|
|
|
data-paths:
|
|
@echo "Project root: $(PROJECT_ROOT)"
|
|
@echo " postgres-data -> $(PROJECT_ROOT)/postgres-data"
|
|
@echo " app-logs -> $(PROJECT_ROOT)/app-logs"
|
|
@echo " dynamicStorage -> $(PROJECT_ROOT)/dynamicStorage"
|
|
@echo " data/ipfs -> $(PROJECT_ROOT)/data/ipfs"
|
|
@echo " data/tusd -> $(PROJECT_ROOT)/data/tusd"
|
|
|
|
nuke destroy:
|
|
@if [ "$(CONFIRM)" != "1" ]; then \
|
|
echo "Set CONFIRM=1 to remove containers, volumes, and local data" >&2; \
|
|
exit 1; \
|
|
fi
|
|
$(COMPOSE) down --remove-orphans --volumes
|
|
rm -rf $(PROJECT_ROOT)/postgres-data $(PROJECT_ROOT)/app-logs $(PROJECT_ROOT)/dynamicStorage $(PROJECT_ROOT)/data
|
|
|
|
# Configure host nginx as reverse proxy for this node using configs/nginx.conf as a template.
|
|
# Usage:
|
|
# sudo make setup-nginx # uses PUBLIC_HOST from .env
|
|
# sudo make setup-nginx DOMAIN=my-public-node-103.projscale.dev
|
|
#
|
|
# This target:
|
|
# - Validates that DOMAIN and ports are known (PUBLIC_HOST/BACKEND_HTTP_PORT/FRONTEND_HTTP_PORT/TUSD_HTTP_PORT)
|
|
# - Stops nginx, obtains/renews a certificate via certbot --standalone (port 80)
|
|
# - Renders /etc/nginx/conf.d/$(DOMAIN).conf from configs/nginx.conf with the correct domain/ports
|
|
# - Starts nginx with the new vhost config
|
|
setup-nginx:
|
|
@if [ "$$(id -u)" -ne 0 ]; then \
|
|
echo "setup-nginx must be run as root (to write /etc/nginx and run certbot)"; \
|
|
exit 1; \
|
|
fi
|
|
@if [ ! -f "$(ENV_FILE)" ]; then \
|
|
echo "$(ENV_FILE) not found; run 'make bootstrap' first." >&2; \
|
|
exit 1; \
|
|
fi
|
|
@if [ -z "$(DOMAIN)" ]; then \
|
|
echo "DOMAIN is not set and PUBLIC_HOST is empty in $(ENV_FILE)." >&2; \
|
|
echo "Set PUBLIC_HOST in .env or pass DOMAIN explicitly, e.g.:" >&2; \
|
|
echo " make setup-nginx DOMAIN=my-public-node-103.projscale.dev" >&2; \
|
|
exit 1; \
|
|
fi
|
|
@if [ -z "$(BACKEND_HTTP_PORT)" ] || [ -z "$(FRONTEND_HTTP_PORT)" ] || [ -z "$(TUSD_HTTP_PORT)" ]; then \
|
|
echo "One of BACKEND_HTTP_PORT/FRONTEND_HTTP_PORT/TUSD_HTTP_PORT is missing in $(ENV_FILE)." >&2; \
|
|
echo "Ensure ./start.sh finished and .env contains these ports, then retry." >&2; \
|
|
exit 1; \
|
|
fi
|
|
@echo "Configuring nginx for domain '$(DOMAIN)' ..."
|
|
@echo " Backend HTTP port: $(BACKEND_HTTP_PORT)"
|
|
@echo " Frontend HTTP port: $(FRONTEND_HTTP_PORT)"
|
|
@echo " tusd HTTP port: $(TUSD_HTTP_PORT)"
|
|
@if ! command -v nginx >/dev/null 2>&1; then \
|
|
echo "nginx binary not found; install nginx (e.g. 'apt install nginx') and retry." >&2; \
|
|
exit 1; \
|
|
fi
|
|
@nginx_conf="/etc/nginx/conf.d/$(DOMAIN).conf"; \
|
|
mkdir -p /etc/nginx/conf.d; \
|
|
if ! command -v certbot >/dev/null 2>&1; then \
|
|
echo "certbot not found; install it (e.g. 'apt install certbot') and rerun 'make setup-nginx'." >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
echo "Stopping nginx (if running) to free port 80 for certbot ..."; \
|
|
systemctl stop nginx 2>/dev/null || nginx -s stop 2>/dev/null || true; \
|
|
echo "Obtaining/renewing TLS certificate via certbot --standalone for $(DOMAIN) ..."; \
|
|
if ! certbot certonly --standalone -d "$(DOMAIN)"; then \
|
|
echo "certbot failed; cannot proceed with nginx SSL setup. Start nginx manually if needed." >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
echo "Rendering nginx vhost config at $$nginx_conf ..."; \
|
|
sed -e 's/my-public-node-8\.projscale\.dev/$(DOMAIN)/g' \
|
|
-e 's|/etc/letsencrypt/live/my-public-node-8\.projscale\.dev/|/etc/letsencrypt/live/$(DOMAIN)/|g' \
|
|
-e 's/server 127\.0\.0\.1:13200;/server 127.0.0.1:$(BACKEND_HTTP_PORT);/' \
|
|
-e 's/server 127\.0\.0\.1:13300;/server 127.0.0.1:$(FRONTEND_HTTP_PORT);/' \
|
|
-e 's/server 127\.0\.0\.1:13400;/server 127.0.0.1:$(TUSD_HTTP_PORT);/' \
|
|
"$(CURDIR)/nginx.conf" > "$$nginx_conf"; \
|
|
if ! nginx -t; then \
|
|
echo "nginx configuration test failed; not starting nginx." >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
echo "Starting nginx with new configuration ..."; \
|
|
systemctl start nginx 2>/dev/null || nginx || true; \
|
|
echo "Nginx setup for $(DOMAIN) complete. Verify HTTPS availability in a browser."
|