diff --git a/.env.example b/.env.example index 3a79f04..d21654f 100644 --- a/.env.example +++ b/.env.example @@ -1,19 +1,7 @@ -# Shared -APP_ENV=development - -# Docs -GITHUB_TOKEN= -RESEND_API_KEY= -RESEND_AUDIENCE_ID= - # Server - Required JWT_SECRET=your-secret-key-min-32-characters ENCRYPTION_KEY=your-32-character-encryption-key -# Database - SQLite (default) -DB_DRIVER=sqlite -DB_CONNECTION=./data/deeploy.db?_pragma=foreign_keys(1)&_pragma=journal_mode(WAL) - -# Database - PostgreSQL (optional) -#DB_DRIVER=pgx -#DB_CONNECTION=postgres://deeploy:deeploy@localhost:5432/deeploy?sslmode=disable +# Notes: +# - APP_ENV is set by runtime context (production in docker-compose, development in local task). +# - All other server settings use code defaults (SQLite, port, build paths, traefik config path). diff --git a/README.md b/README.md index c761398..2509390 100644 --- a/README.md +++ b/README.md @@ -26,20 +26,17 @@ One TUI can manage multiple VPS servers via profiles. Create or switch profiles [deeploy.sh/docs](https://deeploy.sh/docs) +`content/docs` is the source of truth for setup, operations, domains, and pod configuration. + ## Development ```bash -task dev:server # Server (SQLite as default) -task dev:server:postgres # Server (PostgreSQL - confirgure .env) +task dev:server # Server task dev:tui # TUI client task dev:docs # Docs website ``` -For PostgreSQL, set `DB_DRIVER=pgx` in `.env`. - -```bash - -``` +`docker-compose.override.yml` applies local Traefik dev settings and is auto-loaded by Docker Compose in local runs. ## License diff --git a/Taskfile.yml b/Taskfile.yml index 1c6f670..e59b6ed 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,24 +7,19 @@ vars: tasks: # --- Infrastructure --- infra:up: - desc: Start Traefik (for domain testing) + desc: Start Traefik (dev config via docker-compose.override.yml) cmds: - docker compose up -d traefik - infra:postgres: - desc: Start PostgreSQL (for DB_DRIVER=pgx) - cmds: - - docker compose --profile postgres up -d postgres - infra:down: desc: Stop all infrastructure cmds: - - docker compose --profile postgres down + - docker compose down infra:reset: desc: Reset infrastructure (delete volumes and restart) cmds: - - docker compose --profile postgres down -v + - docker compose down -v # --- Install --- install:tui: @@ -54,11 +49,6 @@ tasks: cmds: - task --parallel tailwind templ:server - dev:server:postgres: - desc: Start dev server (PostgreSQL - configure .env) - cmds: - - task --parallel tailwind templ:server infra:postgres - dev:docs: desc: Docs website cmds: diff --git a/content/docs/configuration.md b/content/docs/configuration.md new file mode 100644 index 0000000..c7b997e --- /dev/null +++ b/content/docs/configuration.md @@ -0,0 +1,34 @@ +--- +title: Configuration +description: Server secrets and rotation +order: 3 +--- + +deeploy generates secure server secrets automatically on first install. + +## Server Secrets + +- `JWT_SECRET` +- `ENCRYPTION_KEY` + +The install script generates both automatically on first install and writes them to `/opt/deeploy/.env`. + +You normally do not need to touch them. + +## Important + +- Change `ENCRYPTION_KEY` only before you store real data. +- If you change `ENCRYPTION_KEY` later, previously encrypted values in the database cannot be decrypted. +- Changing `JWT_SECRET` logs out existing sessions (users must log in again). + +## If You Must Change Secrets + +1. SSH to your server. +2. Open `/opt/deeploy/.env`. +3. Replace the secret(s). +4. Restart the stack: + ```bash + cd /opt/deeploy + docker compose up -d --force-recreate + ``` +5. Verify login and app behavior. diff --git a/content/docs/deploying.md b/content/docs/deploying.md index 1ca4d71..74b5010 100644 --- a/content/docs/deploying.md +++ b/content/docs/deploying.md @@ -1,7 +1,7 @@ --- title: Deploying description: Deploy your first app -order: 3 +order: 4 --- Deploy your first application step by step. @@ -24,16 +24,32 @@ A pod is a single deployable application. One pod = one container. - **Branch** - The branch to deploy (default: `main`) - **Dockerfile** - Path to your Dockerfile (default: `Dockerfile`) -For private repositories, you'll need to add a [Git Token](/docs/private-repos) first. +For private repositories, select a Git token in the pod form. +Git tokens are managed in **Settings → Tokens** (create/edit/delete there). -## 3. Add a Domain +If your app needs runtime config, add it in [Pod Environment Variables](/docs/pod-env-vars). + +## 3. Set Pod Vars (Optional) + +If your app needs runtime variables: + +1. Open the pod +2. Go to **Vars** (`4`) +3. Press `e` to edit +4. Save with `Ctrl+S` + +Then restart or redeploy the pod to apply changes. + +## 4. Add a Domain Your pod needs a domain to be accessible. You have two options: - **Auto-generated** - Instant subdomain like `pod-abc123.1.2.3.4.sslip.io` - **Custom** - Your own domain like `myapp.example.com` (requires [DNS setup](/docs/domains)) -## 4. Deploy +After domain changes, run **Deploy** or **Restart** so routing updates are applied. + +## 5. Deploy / Restart Hit "Deploy" and watch the build logs. The process: @@ -54,4 +70,6 @@ Once complete, your app is live at the domain URL. **Redeploy** - Pull latest code and rebuild +**Vars** - Edit runtime environment variables for the pod + To update your app, just push to your repository and hit "Deploy" again. diff --git a/content/docs/domains.md b/content/docs/domains.md index 69900dd..4d5b414 100644 --- a/content/docs/domains.md +++ b/content/docs/domains.md @@ -1,7 +1,7 @@ --- title: Domains description: Custom domains and HTTPS setup -order: 4 +order: 6 --- ## Server Domain @@ -29,10 +29,21 @@ order: 4 **Note:** Ports 80 and 443 must be open on your server for SSL to work. +### Verify Server HTTPS + +After setting the server domain: + +1. Confirm your TUI profile/server URL uses `https://...` +2. Confirm certificate provisioning completed successfully +3. If it fails, verify DNS propagation and that ports 80/443 are open + ## Pod Domains Each pod needs at least one domain to be accessible. +Domain changes are not applied to a running container automatically. +After adding, editing, or deleting pod domains, run **Deploy** or **Restart** to apply routing changes. + ### Auto-Generated Domains The quickest way to get started. Deeploy generates a subdomain using [sslip.io](https://sslip.io): @@ -58,7 +69,7 @@ For production apps, use your own domain: Pod → Domains → New → Enter `myapp.example.com` -3. **Deploy** +3. **Deploy or Restart** SSL certificate is automatically provisioned. diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index 3de7d86..baf2b08 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -6,6 +6,8 @@ order: 2 Get up and running with deeploy in minutes. +No manual environment-variable setup is required for the standard installation. + ## Requirements **Server (VPS)** @@ -25,6 +27,8 @@ SSH into your VPS and run: curl -fsSL https://deeploy.sh/server.sh | sudo bash ``` +On first install, the script generates required server secrets automatically. + ### Options ```bash @@ -39,10 +43,7 @@ curl -fsSL https://deeploy.sh/server.sh | sudo bash -s v0.1.0 SQLite is used by default - zero configuration needed. -For PostgreSQL (advanced users): -```bash -curl -fsSL https://deeploy.sh/server.sh | sudo bash -s -- --postgres -``` +For full server config details, see [Configuration](/docs/configuration). ## Install TUI @@ -63,6 +64,8 @@ curl -fsSL https://deeploy.sh/tui.sh | bash -s v0.1.0 Run `deeploy` to launch the TUI and connect to your server. +After connecting, set your [Server Domain](/docs/domains) to enable HTTPS between TUI and server. + After first login, you can add more servers as separate profiles and switch between them later. This lets you manage multiple VPS instances from one local TUI setup. diff --git a/content/docs/introduction.md b/content/docs/introduction.md index f565e37..b1049aa 100644 --- a/content/docs/introduction.md +++ b/content/docs/introduction.md @@ -13,7 +13,7 @@ order: 1 - Instant domains via sslip.io wildcard DNS - Terminal-first UI (TUI) - Self-hosted, you own your data -- SQLite by default, PostgreSQL optional +- SQLite ## Currently Supported diff --git a/content/docs/pod-env-vars.md b/content/docs/pod-env-vars.md new file mode 100644 index 0000000..390fc04 --- /dev/null +++ b/content/docs/pod-env-vars.md @@ -0,0 +1,46 @@ +--- +title: Pod Environment Variables +description: Manage runtime environment variables for your pods +order: 7 +--- + +Use Pod Environment Variables (Vars tab) to provide runtime config to your app containers. + +## Where to Edit + +In the TUI: + +1. Open a pod +2. Switch to the **Vars** tab (`4` or `[` / `]`) +3. Press `e` to edit +4. Enter variables in `KEY=value` format (one per line) +5. Press `Ctrl+S` to save + +## Format Rules + +- One variable per line +- Format must be `KEY=value` +- Empty lines are ignored +- Duplicate keys are resolved by last entry + +## When Changes Apply + +Saved vars are stored for the pod and applied to the container on deploy/redeploy/restart. + +Recommended flow after changes: + +1. Save vars in **Vars** tab +2. Trigger **Restart** (`R`) or **Deploy** (`D`) + +## Security Notes + +- Pod vars are stored encrypted server-side +- They are used for container runtime environment injection +- Keep secrets out of repository files and Dockerfiles when possible + +## Common Mistakes + +- Missing `=` in a line +- Trailing spaces in keys +- Editing vars but forgetting to restart/redeploy +- Setting app vars in server config instead of pod vars diff --git a/content/docs/private-repos.md b/content/docs/private-repos.md index 5ffe1c9..44580b7 100644 --- a/content/docs/private-repos.md +++ b/content/docs/private-repos.md @@ -1,7 +1,7 @@ --- title: Private Repositories description: Deploy from private Git repositories -order: 5 +order: 8 --- To deploy from private repositories, you need to add a Git token. diff --git a/content/docs/tui.md b/content/docs/tui.md index fa3bc8e..a6de503 100644 --- a/content/docs/tui.md +++ b/content/docs/tui.md @@ -1,7 +1,7 @@ --- title: Using the TUI description: Navigate the terminal interface -order: 6 +order: 5 --- The deeploy TUI (Terminal User Interface) is built for keyboard-driven workflows. @@ -46,6 +46,8 @@ Inside a pod, use: - `n`, `g`, `o`, `e`, `d` for domain actions (Domains tab) - `e` to edit vars, `Ctrl+S` to save, `Esc` to cancel (Vars tab) +For detailed vars behavior and best practices, see [Pod Environment Variables](/docs/pod-env-vars). + ## Themes Open themes from the **Settings** panel: diff --git a/content/docs/updating.md b/content/docs/updating.md index 724946c..8bdec38 100644 --- a/content/docs/updating.md +++ b/content/docs/updating.md @@ -1,7 +1,7 @@ --- title: Updating description: Update deeploy to the latest version -order: 7 +order: 9 --- ## Update Server @@ -14,6 +14,12 @@ curl -fsSL https://deeploy.sh/server.sh | sudo bash This pulls the latest Docker image and restarts the server. Your data is preserved. +What is preserved: + +- Existing `.env` with your generated secrets +- Database data in mounted volumes +- Existing deployment records/projects/pods + ### Specific Version ```bash @@ -37,3 +43,12 @@ curl -fsSL https://deeploy.sh/tui.sh | bash -s v0.2.0 ## Check Version The TUI shows your current version and the latest available version in the Settings info panel and status/header area. + +## Quick Verification After Update + +1. Check health endpoint: + ```bash + curl -fsSL http://YOUR_SERVER_IP:8090/api/health + ``` +2. Open the TUI and confirm server/version info is visible. +3. Open an existing pod and verify logs/deploy actions work. diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 6a9206b..1ab3554 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,49 +1,31 @@ -# Dev overrides - auto-loaded by "docker compose up" -# This file OVERRIDES docker-compose.yml settings for local development +# Purpose: +# - Local dev/testing convenience for Traefik. +# - Keep production compose unchanged. # -# Key differences from production: -# - No HTTPS/SSL (Let's Encrypt won't work on localhost) -# - No HTTP→HTTPS redirect -# - Traefik dashboard enabled for debugging -# - Deeploy app disabled (we run via "go run" instead) +# Load behavior: +# - Docker Compose loads this file automatically together with docker-compose.yml +# when you run commands like `docker compose up`. +# +# What this file changes vs base compose: +# - Traefik runs in dev mode (HTTP only + dashboard on :8080). +# - `deeploy` service is disabled here (server runs via `go run ./cmd/server` in dev). +# +# Important: +# - `command` replaces the base command entirely, so required runtime flags stay here. services: - # PostgreSQL - only starts with: docker compose --profile postgres up - postgres: - profiles: [postgres] - ports: - - "127.0.0.1:5432:5432" # Localhost only for TablePlus etc. - traefik: command: - #───────────────────────────────────────────────────────────────────────── - # DEV CONFIG: HTTP only, no SSL - # Production uses HTTPS + Let's Encrypt, but that won't work on localhost - #───────────────────────────────────────────────────────────────────────── - - # Docker provider (same as prod) - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=deeploy" - - # HTTP only - no HTTPS entrypoint, no redirect - "--entrypoints.web.address=:80" - - # DEV ONLY: Enable dashboard without auth (insecure!) - # Access at http://localhost:8080 + - "--providers.file.directory=/traefik/dynamic" + - "--providers.file.watch=true" - "--api.insecure=true" - - # NOTE: No ACME/Let's Encrypt config here - # SSL certificates require a real domain reachable from the internet ports: - - "80:80" - # DEV ONLY: Traefik dashboard for debugging routing - "8080:8080" - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - # No letsencrypt volume needed for dev deeploy: - # Disable in dev - we run via "go run" instead profiles: - prod-only diff --git a/docker-compose.yml b/docker-compose.yml index 2856ec8..242c267 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ -# Production-ready config -# Dev: auto-loads docker-compose.override.yml -# Prod: install script uses only this file +# Production-ready config. +# Dev overrides are in docker-compose.override.yml. +# Docker Compose auto-loads both files during normal local `docker compose` commands. # THE NETWORK: All containers that need to talk to each other must be here. # Traefik routes traffic -> needs to reach containers -> must be in same network. @@ -11,26 +11,6 @@ networks: name: deeploy services: - # PostgreSQL - Optional, only starts with --profile postgres - postgres: - profiles: [postgres] - image: postgres:16-alpine - container_name: deeploy-postgres - networks: - - deeploy - environment: - POSTGRES_USER: deeploy - POSTGRES_PASSWORD: deeploy - POSTGRES_DB: deeploy - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U deeploy"] - interval: 5s - timeout: 5s - retries: 5 - restart: unless-stopped - traefik: image: traefik:v3.6 container_name: deeploy-traefik @@ -122,15 +102,15 @@ services: - /var/run/docker.sock:/var/run/docker.sock # Dynamic config: App writes Traefik config files here (server domain routing) - /opt/deeploy/traefik:/traefik/dynamic - # SQLite database file (only used when DB_DRIVER=sqlite) + # SQLite database file - /opt/deeploy/data:/data environment: + APP_ENV: production JWT_SECRET: ${JWT_SECRET} ENCRYPTION_KEY: ${ENCRYPTION_KEY} restart: unless-stopped volumes: - postgres_data: # Let's Encrypt certificates storage # Persists SSL certs across container restarts to avoid rate limits letsencrypt_certs: diff --git a/go.mod b/go.mod index 1bf2dbd..8117067 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/docker/go-connections v0.6.0 github.com/golang-jwt/jwt/v4 v4.5.2 github.com/google/uuid v1.6.0 - github.com/jackc/pgx/v5 v5.7.4 github.com/jmoiron/sqlx v1.4.0 github.com/joho/godotenv v1.5.1 github.com/pressly/goose/v3 v3.24.3 @@ -53,9 +52,6 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/go.sum b/go.sum index 7357389..5f0f372 100644 --- a/go.sum +++ b/go.sum @@ -99,14 +99,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= -github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= -github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= -github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -179,7 +171,6 @@ github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLy github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= diff --git a/internal/docs/ui/pages/landing.templ b/internal/docs/ui/pages/landing.templ index cadabf4..93dbc1e 100644 --- a/internal/docs/ui/pages/landing.templ +++ b/internal/docs/ui/pages/landing.templ @@ -73,7 +73,7 @@ templ Landing() {

Built with

-

Go · Bubble Tea · Docker · Traefik · Let's Encrypt · PostgreSQL

+

Go · Bubble Tea · Docker · Traefik · Let's Encrypt · SQLite

diff --git a/internal/server/app/app.go b/internal/server/app/app.go index 4ef3962..e050716 100644 --- a/internal/server/app/app.go +++ b/internal/server/app/app.go @@ -25,7 +25,7 @@ type App struct { } func New(cfg *config.Config) (*App, error) { - database, err := db.Init(cfg.DBDriver, cfg.DBConnection) + database, err := db.Init(cfg.DBConnection) if err != nil { return nil, err } diff --git a/internal/server/config/config.go b/internal/server/config/config.go index 5fe0abd..edb730f 100644 --- a/internal/server/config/config.go +++ b/internal/server/config/config.go @@ -10,13 +10,12 @@ import ( type Config struct { AppEnv string Port string - DBDriver string // "sqlite" or "pgx" - DBConnection string // connection string + DBConnection string JWTSecret string EncryptionKey string CookieSecure bool BuildDir string - TraefikConfigDir string // Directory for Traefik dynamic config files + TraefikConfigDir string } func Load() *Config { @@ -24,25 +23,19 @@ func Load() *Config { appEnv := getEnv("APP_ENV", "development") - // Database config - SQLite default, PostgreSQL optional - dbDriver := getEnv("DB_DRIVER", "sqlite") - dbConnection := getEnv("DB_CONNECTION", getDBConnectionDefault()) - // Always require secrets (generated by install script) jwtSecret := requireEnv("JWT_SECRET", "min 32 characters") encryptionKey := requireEnv("ENCRYPTION_KEY", "exactly 32 characters") - cookieSecure := getEnvBool("COOKIE_SECURE", appEnv == "production") return &Config{ AppEnv: appEnv, - Port: getEnv("PORT", "8090"), - DBDriver: dbDriver, - DBConnection: dbConnection, + Port: "8090", + DBConnection: getDBConnectionDefault(), JWTSecret: jwtSecret, EncryptionKey: encryptionKey, - CookieSecure: cookieSecure, - BuildDir: getEnv("BUILD_DIR", "/tmp/deeploy-builds"), - TraefikConfigDir: getEnv("TRAEFIK_CONFIG_DIR", "/traefik/dynamic"), + CookieSecure: appEnv == "production", + BuildDir: "/tmp/deeploy-builds", + TraefikConfigDir: "/traefik/dynamic", } } @@ -62,20 +55,6 @@ func getEnv(key, fallback string) string { return value } -func getEnvBool(key string, fallback bool) bool { - value, exists := os.LookupEnv(key) - if !exists || value == "" { - return fallback - } - if value == "1" || value == "true" || value == "TRUE" || value == "True" { - return true - } - if value == "0" || value == "false" || value == "FALSE" || value == "False" { - return false - } - return fallback -} - func requireEnv(key, hint string) string { value := os.Getenv(key) if value == "" { diff --git a/internal/server/db/db.go b/internal/server/db/db.go index ae4638e..14465d8 100644 --- a/internal/server/db/db.go +++ b/internal/server/db/db.go @@ -10,7 +10,6 @@ import ( "strings" "time" - _ "github.com/jackc/pgx/v5/stdlib" "github.com/jmoiron/sqlx" "github.com/pressly/goose/v3" _ "modernc.org/sqlite" @@ -19,38 +18,21 @@ import ( //go:embed migrations/*.sql var migrations embed.FS -// dialectMap maps database drivers to Goose dialect names -var dialectMap = map[string]string{ - "sqlite": "sqlite3", - "pgx": "postgres", -} - -// getDialect returns the Goose dialect for the given driver -func getDialect(driver string) string { - dialect, ok := dialectMap[driver] - if ok { - return dialect - } - return driver -} - -func Init(driver, connection string) (*sqlx.DB, error) { +func Init(connection string) (*sqlx.DB, error) { // SQLite: create data directory if needed - if driver == "sqlite" { - // Extract path before query params (e.g., "./data/deeploy.db?_pragma=...") - dbPath := connection - idx := strings.Index(connection, "?") - if idx != -1 { - dbPath = connection[:idx] - } - dir := filepath.Dir(dbPath) - err := os.MkdirAll(dir, 0755) - if err != nil { - return nil, fmt.Errorf("failed to create data directory: %w", err) - } + // Extract path before query params (e.g., "./data/deeploy.db?_pragma=...") + dbPath := connection + idx := strings.Index(connection, "?") + if idx != -1 { + dbPath = connection[:idx] + } + dir := filepath.Dir(dbPath) + err := os.MkdirAll(dir, 0755) + if err != nil { + return nil, fmt.Errorf("failed to create data directory: %w", err) } - db, err := sqlx.Connect(driver, connection) + db, err := sqlx.Connect("sqlite", connection) if err != nil { return nil, fmt.Errorf("failed to connect: %w", err) } @@ -60,10 +42,10 @@ func Init(driver, connection string) (*sqlx.DB, error) { db.SetMaxIdleConns(5) db.SetConnMaxLifetime(5 * time.Minute) - slog.Info("database connected", "driver", driver) + slog.Info("database connected", "driver", "sqlite") // Run migrations - err = runMigrations(db, driver) + err = runMigrations(db) if err != nil { return nil, err } @@ -71,9 +53,8 @@ func Init(driver, connection string) (*sqlx.DB, error) { return db, nil } -func runMigrations(db *sqlx.DB, driver string) error { - // Set dialect based on driver - err := goose.SetDialect(getDialect(driver)) +func runMigrations(db *sqlx.DB) error { + err := goose.SetDialect("sqlite3") if err != nil { return fmt.Errorf("failed to set dialect: %w", err) } diff --git a/scripts/server.sh b/scripts/server.sh index a487f64..a5a6e93 100644 --- a/scripts/server.sh +++ b/scripts/server.sh @@ -12,19 +12,7 @@ if [[ $EUID -ne 0 ]]; then fi # Parse arguments -USE_POSTGRES=false -VERSION="latest" - -for arg in "$@"; do - case $arg in - --postgres) - USE_POSTGRES=true - ;; - *) - VERSION="$arg" - ;; - esac -done +VERSION="${1:-latest}" # Resolve "latest" to the actual latest release tag from GitHub # For bleeding-edge, use: ./server.sh main @@ -75,14 +63,7 @@ JWT_SECRET=$JWT_SECRET ENCRYPTION_KEY=$ENCRYPTION_KEY EOF - # PostgreSQL needs explicit config (SQLite auto-detects path via /.dockerenv) - if [[ "$USE_POSTGRES" == "true" ]]; then - echo "DB_DRIVER=pgx" >> .env - echo "DB_CONNECTION=postgres://deeploy:deeploy@deeploy-postgres:5432/deeploy?sslmode=disable" >> .env - echo "Using PostgreSQL database" - else - echo "Using SQLite database (default)" - fi + echo "Using SQLite database" chmod 600 .env fi @@ -91,11 +72,7 @@ fi echo "Starting deeploy..." DEEPLOY_VERSION=$TAG docker compose pull -if [[ "$USE_POSTGRES" == "true" ]]; then - COMPOSE_PROFILES=postgres DEEPLOY_VERSION=$TAG docker compose up -d --force-recreate -else - DEEPLOY_VERSION=$TAG docker compose up -d --force-recreate -fi +DEEPLOY_VERSION=$TAG docker compose up -d --force-recreate IP=$(hostname -I | awk '{print $1}') URL="http://$IP:8090" diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 5dc90f6..4bf79f5 100644 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -17,7 +17,7 @@ fi echo "=== Deeploy Uninstall ===" echo "This will remove ALL deeploy data including:" echo " - All deployed pods (deeploy-* containers)" -echo " - Deeploy stack (postgres, traefik, app)" +echo " - Deeploy stack (traefik, app)" echo " - All images" echo " - Database data" echo "" @@ -40,12 +40,9 @@ echo "Removing deeploy images..." docker images --filter "reference=deeploy-*" --format "{{.ID}}" | xargs -r docker rmi -f 2>/dev/null || true # Remove stack images (fails silently if still used by other containers) docker rmi -f ghcr.io/deeploy-sh/deeploy 2>/dev/null || true -docker rmi -f postgres 2>/dev/null || true docker rmi -f traefik 2>/dev/null || true echo "Removing docker volumes..." -docker volume rm deeploy_postgres_data 2>/dev/null || true -docker volume rm postgres_data 2>/dev/null || true # SSL certificates volume (Let's Encrypt) docker volume rm deeploy_letsencrypt_certs 2>/dev/null || true docker volume rm letsencrypt_certs 2>/dev/null || true