initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
docker/nginx/certs/** filter=git-crypt diff=git-crypt
|
||||||
|
docker/nginx/data/keys.json filter=git-crypt diff=git-crypt
|
||||||
|
docker/nginx/data/database.sqlite filter=git-crypt diff=git-crypt
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
name: Deploy nginx
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'docker/nginx/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Deploy via SSH
|
||||||
|
uses: appleboy/ssh-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
username: deploy
|
||||||
|
key: ${{ secrets.DEPLOY_KEY }}
|
||||||
|
script: deploy-nginx
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
name: Deploy timothykim.net
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'docker/timothykim.net/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Deploy via SSH
|
||||||
|
uses: appleboy/ssh-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
username: deploy
|
||||||
|
key: ${{ secrets.DEPLOY_KEY }}
|
||||||
|
script: deploy-timothykim
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
containerd/
|
||||||
|
vultr/
|
||||||
|
docker/nginx/data/logs/
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# hantim-server
|
||||||
|
|
||||||
|
Server provisioning and app management for the hantim webserver. This repo
|
||||||
|
lives at `/opt` on the server and contains Docker Compose configs, deploy
|
||||||
|
scripts, and Gitea Actions workflows for each app.
|
||||||
|
|
||||||
|
## Repo structure
|
||||||
|
|
||||||
|
```
|
||||||
|
docker/ # One directory per app, each with a compose.yml
|
||||||
|
nginx/ # Nginx Proxy Manager (reverse proxy + TLS)
|
||||||
|
timothykim.net/ # timothykim.net static site
|
||||||
|
scripts/
|
||||||
|
deploy-dispatch.sh # SSH command dispatcher (routes to per-app deploy scripts)
|
||||||
|
deploy-nginx.sh # Deploy script for nginx
|
||||||
|
deploy-timothykim.sh # Deploy script for timothykim.net
|
||||||
|
new-app.sh # Scaffolding script to add a new app
|
||||||
|
setup.sh # One-time server provisioning script
|
||||||
|
.gitea/workflows/ # Per-app deploy workflows triggered by path changes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Initial server setup
|
||||||
|
|
||||||
|
On a fresh Rocky Linux 9 (or compatible) install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dnf install -y git git-crypt
|
||||||
|
git clone <repo-url> /opt
|
||||||
|
git-crypt unlock /path/to/git-crypt-key
|
||||||
|
/opt/setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`setup.sh` installs Docker, creates a `deploy` user, sets up the shared Docker
|
||||||
|
network, and starts all services. See the script for the full list of post-setup
|
||||||
|
steps (registry login, Nginx Proxy Manager config, etc.).
|
||||||
|
|
||||||
|
## How deploys work
|
||||||
|
|
||||||
|
Each app has three components:
|
||||||
|
|
||||||
|
1. **Deploy script** (`scripts/deploy-<app>.sh`) -- pulls the latest repo
|
||||||
|
changes, then runs `docker compose pull && up -d` for that app.
|
||||||
|
2. **Gitea Actions workflow** (`.gitea/workflows/deploy-<app>.yml`) -- triggers
|
||||||
|
on pushes to `main` when files under `docker/<app>/` change. SSHes into the
|
||||||
|
server as the `deploy` user to trigger the deploy.
|
||||||
|
3. **SSH dispatcher** (`scripts/deploy-dispatch.sh`) -- the `deploy` user's
|
||||||
|
`authorized_keys` is locked to this script via a `command=` directive. It
|
||||||
|
reads `SSH_ORIGINAL_COMMAND` to route to the correct per-app deploy script.
|
||||||
|
|
||||||
|
This means:
|
||||||
|
|
||||||
|
- Pushing a change to `docker/nginx/compose.yml` only deploys nginx.
|
||||||
|
- Pushing a change to `scripts/` or `setup.sh` does not trigger any deploy.
|
||||||
|
- Each app deploys independently.
|
||||||
|
|
||||||
|
## Adding a new app
|
||||||
|
|
||||||
|
Run the scaffolding script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/new-app.sh <app-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates:
|
||||||
|
|
||||||
|
- `docker/<app-name>/compose.yml` -- a starter compose file on the `shared`
|
||||||
|
network
|
||||||
|
- `scripts/deploy-<app-name>.sh` -- the deploy script
|
||||||
|
- `.gitea/workflows/deploy-<app-name>.yml` -- the Gitea Actions workflow
|
||||||
|
- A new case in `scripts/deploy-dispatch.sh`
|
||||||
|
|
||||||
|
After running the script:
|
||||||
|
|
||||||
|
1. Edit `docker/<app-name>/compose.yml` to fit your app (image, ports,
|
||||||
|
volumes, environment variables, etc.).
|
||||||
|
2. Commit and push to `main`.
|
||||||
|
3. Configure the proxy host in Nginx Proxy Manager to route traffic to the new
|
||||||
|
service.
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
|
Nginx Proxy Manager certs and Let's Encrypt account keys are encrypted with
|
||||||
|
git-crypt (see `.gitattributes`). You need the git-crypt key to unlock them.
|
||||||
|
|
||||||
|
The following secrets must be configured in the Gitea repo settings for
|
||||||
|
deploys to work:
|
||||||
|
|
||||||
|
- `DEPLOY_HOST` -- the server's IP or hostname
|
||||||
|
- `DEPLOY_KEY` -- the SSH private key for the `deploy` user
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-1/cert1.pem
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-1/chain1.pem
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-1/fullchain1.pem
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-1/privkey1.pem
|
||||||
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-2/cert1.pem
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-2/chain1.pem
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-2/fullchain1.pem
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-2/privkey1.pem
|
||||||
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-3/cert1.pem
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-3/chain1.pem
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-3/fullchain1.pem
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../archive/npm-3/privkey1.pem
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: 'jc21/nginx-proxy-manager:latest'
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- shared
|
||||||
|
ports:
|
||||||
|
- '80:80'
|
||||||
|
- '443:443'
|
||||||
|
- '81:81'
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./certs:/etc/letsencrypt
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared:
|
||||||
|
name: shared
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,20 @@
|
|||||||
|
# ------------------------------------------------------------
|
||||||
|
# Default Site
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default;
|
||||||
|
listen [::]:80 default;
|
||||||
|
|
||||||
|
server_name default-host.localhost;
|
||||||
|
access_log /data/logs/default-host_access.log combined;
|
||||||
|
error_log /data/logs/default-host_error.log warn;
|
||||||
|
|
||||||
|
|
||||||
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# ------------------------------------------------------------
|
||||||
|
# www.timothykim.net
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
map $scheme $hsts_header {
|
||||||
|
https "max-age=63072000; preload";
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
set $forward_scheme http;
|
||||||
|
set $server "static";
|
||||||
|
set $port 80;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
|
||||||
|
|
||||||
|
server_name www.timothykim.net;
|
||||||
|
http2 off;
|
||||||
|
|
||||||
|
|
||||||
|
# Let's Encrypt SSL
|
||||||
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
include conf.d/include/ssl-cache.conf;
|
||||||
|
include conf.d/include/ssl-ciphers.conf;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/npm-3/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/npm-3/privkey.pem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Asset Caching
|
||||||
|
include conf.d/include/assets.conf;
|
||||||
|
|
||||||
|
|
||||||
|
# Block Exploits
|
||||||
|
include conf.d/include/block-exploits.conf;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Force SSL
|
||||||
|
|
||||||
|
set $trust_forwarded_proto "F";
|
||||||
|
|
||||||
|
include conf.d/include/force-ssl.conf;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
|
||||||
|
access_log /data/logs/proxy-host-1_access.log proxy;
|
||||||
|
error_log /data/logs/proxy-host-1_error.log warn;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
location / {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy!
|
||||||
|
include conf.d/include/proxy.conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Custom
|
||||||
|
include /data/nginx/custom/server_proxy[.]conf;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# ------------------------------------------------------------
|
||||||
|
# timothykim.net
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
map $scheme $hsts_header {
|
||||||
|
https "max-age=63072000; preload";
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
set $forward_scheme http;
|
||||||
|
set $server "static";
|
||||||
|
set $port 80;
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
|
||||||
|
|
||||||
|
server_name timothykim.net;
|
||||||
|
|
||||||
|
http2 on;
|
||||||
|
|
||||||
|
|
||||||
|
# Let's Encrypt SSL
|
||||||
|
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||||
|
include conf.d/include/ssl-cache.conf;
|
||||||
|
include conf.d/include/ssl-ciphers.conf;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/npm-2/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/npm-2/privkey.pem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Asset Caching
|
||||||
|
include conf.d/include/assets.conf;
|
||||||
|
|
||||||
|
|
||||||
|
# Block Exploits
|
||||||
|
include conf.d/include/block-exploits.conf;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Force SSL
|
||||||
|
|
||||||
|
set $trust_forwarded_proto "F";
|
||||||
|
|
||||||
|
include conf.d/include/force-ssl.conf;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
|
||||||
|
access_log /data/logs/proxy-host-2_access.log proxy;
|
||||||
|
error_log /data/logs/proxy-host-2_error.log warn;
|
||||||
|
|
||||||
|
return 301 https://www.timothykim.net$request_uri;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
location / {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $http_connection;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy!
|
||||||
|
include conf.d/include/proxy.conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Custom
|
||||||
|
include /data/nginx/custom/server_proxy[.]conf;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
static:
|
||||||
|
image: git.timothykim.net/timothykim/static:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- shared
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
case "$SSH_ORIGINAL_COMMAND" in
|
||||||
|
deploy-nginx) /opt/scripts/deploy-nginx.sh ;;
|
||||||
|
deploy-timothykim) /opt/scripts/deploy-timothykim.sh ;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: $SSH_ORIGINAL_COMMAND"
|
||||||
|
echo "Available: deploy-nginx, deploy-timothykim"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cd /opt && git pull && cd docker/nginx && docker compose pull && docker compose up -d
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cd /opt && git pull && cd docker/timothykim.net && docker compose pull && docker compose up -d
|
||||||
Executable
+79
@@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -z "${1:-}" ]; then
|
||||||
|
echo "Usage: ./scripts/new-app.sh <app-name>"
|
||||||
|
echo "Example: ./scripts/new-app.sh my-blog"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
APP="$1"
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
|
||||||
|
if [ -d "$REPO_ROOT/docker/$APP" ]; then
|
||||||
|
echo "Error: docker/$APP already exists."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Creating docker/$APP/compose.yml..."
|
||||||
|
mkdir -p "$REPO_ROOT/docker/$APP"
|
||||||
|
cat > "$REPO_ROOT/docker/$APP/compose.yml" <<EOF
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: git.timothykim.net/timothykim/$APP:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- shared
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared:
|
||||||
|
external: true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Creating scripts/deploy-$APP.sh..."
|
||||||
|
cat > "$REPO_ROOT/scripts/deploy-$APP.sh" <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
cd /opt && git pull && cd docker/$APP && docker compose pull && docker compose up -d
|
||||||
|
EOF
|
||||||
|
chmod +x "$REPO_ROOT/scripts/deploy-$APP.sh"
|
||||||
|
|
||||||
|
echo "Adding $APP to deploy-dispatch.sh..."
|
||||||
|
sed -i "/^ \*)$/i\\ deploy-$APP) /opt/scripts/deploy-$APP.sh ;;" \
|
||||||
|
"$REPO_ROOT/scripts/deploy-dispatch.sh"
|
||||||
|
|
||||||
|
echo "Creating .gitea/workflows/deploy-$APP.yml..."
|
||||||
|
mkdir -p "$REPO_ROOT/.gitea/workflows"
|
||||||
|
cat > "$REPO_ROOT/.gitea/workflows/deploy-$APP.yml" <<'OUTER'
|
||||||
|
name: Deploy APP_PLACEHOLDER
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'docker/APP_PLACEHOLDER/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Deploy via SSH
|
||||||
|
uses: appleboy/ssh-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
username: deploy
|
||||||
|
key: ${{ secrets.DEPLOY_KEY }}
|
||||||
|
script: deploy-APP_PLACEHOLDER
|
||||||
|
OUTER
|
||||||
|
sed -i "s/APP_PLACEHOLDER/$APP/g" "$REPO_ROOT/.gitea/workflows/deploy-$APP.yml"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! Files created:"
|
||||||
|
echo " - docker/$APP/compose.yml"
|
||||||
|
echo " - scripts/deploy-$APP.sh"
|
||||||
|
echo " - .gitea/workflows/deploy-$APP.yml"
|
||||||
|
echo " - Updated scripts/deploy-dispatch.sh"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Edit docker/$APP/compose.yml to fit your app"
|
||||||
|
echo " 2. Commit and push to deploy"
|
||||||
|
echo " 3. Configure the proxy host in Nginx Proxy Manager"
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Server setup script for a fresh Rocky Linux 9 (or compatible) install.
|
||||||
|
# Run as root after cloning the repo to /opt/.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# 1. dnf install -y git git-crypt
|
||||||
|
# 2. git clone <repo-url> /opt
|
||||||
|
# 3. git-crypt unlock /path/to/git-crypt-key
|
||||||
|
# 4. /opt/setup.sh
|
||||||
|
#
|
||||||
|
|
||||||
|
errors=()
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
errors+=("Not running as root. Please run this script as root.")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v git &>/dev/null; then
|
||||||
|
errors+=("git is not installed. Run: dnf install -y git git-crypt")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v git-crypt &>/dev/null; then
|
||||||
|
errors+=("git-crypt is not installed. Run: dnf install -y git git-crypt")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(pwd)" != "/opt" ] && [ "$(dirname "$(readlink -f "$0")")" != "/opt" ]; then
|
||||||
|
errors+=("Repo does not appear to be cloned to /opt. Run: git clone <repo-url> /opt")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git-crypt status &>/dev/null && git-crypt status 2>/dev/null | grep -q '^\*\*\*ENCRYPTED\*\*\*'; then
|
||||||
|
errors+=("git-crypt has not been unlocked. Run: git-crypt unlock /path/to/git-crypt-key")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#errors[@]} -gt 0 ]; then
|
||||||
|
echo "ERROR: Prerequisites not met."
|
||||||
|
echo ""
|
||||||
|
echo "Please complete the initial setup before running this script:"
|
||||||
|
echo " 1. dnf install -y git git-crypt"
|
||||||
|
echo " 2. git clone <repo-url> /opt"
|
||||||
|
echo " 3. git-crypt unlock /path/to/git-crypt-key"
|
||||||
|
echo " 4. /opt/setup.sh"
|
||||||
|
echo ""
|
||||||
|
echo "Issues found:"
|
||||||
|
for err in "${errors[@]}"; do
|
||||||
|
echo " - $err"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Installing Docker..."
|
||||||
|
dnf install -y dnf-plugins-core
|
||||||
|
dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
|
||||||
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
|
systemctl enable --now docker
|
||||||
|
|
||||||
|
echo "==> Creating deploy user..."
|
||||||
|
useradd -r -s /usr/sbin/nologin deploy
|
||||||
|
usermod -aG docker deploy
|
||||||
|
|
||||||
|
echo "==> Setting up deploy SSH key..."
|
||||||
|
mkdir -p /home/deploy/.ssh
|
||||||
|
chmod 700 /home/deploy/.ssh
|
||||||
|
if [ ! -f /home/deploy/.ssh/authorized_keys ]; then
|
||||||
|
echo "WARNING: Add the CI public key manually:"
|
||||||
|
echo ' command="/opt/scripts/deploy-dispatch.sh",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-ed25519 <KEY>'
|
||||||
|
echo " into /home/deploy/.ssh/authorized_keys"
|
||||||
|
fi
|
||||||
|
chown -R deploy:deploy /home/deploy/.ssh
|
||||||
|
|
||||||
|
echo "==> Making scripts executable..."
|
||||||
|
chmod +x /opt/scripts/*.sh
|
||||||
|
|
||||||
|
echo "==> Creating shared Docker network..."
|
||||||
|
docker network create shared || true
|
||||||
|
|
||||||
|
echo "==> Logging into Gitea registry..."
|
||||||
|
echo "Run manually: docker login git.timothykim.net"
|
||||||
|
|
||||||
|
echo "==> Starting services..."
|
||||||
|
cd /opt/docker/nginx && docker compose up -d
|
||||||
|
cd /opt/docker/timothykim.net && docker compose up -d
|
||||||
|
|
||||||
|
echo "==> Done. Don't forget to:"
|
||||||
|
echo " 1. Add the deploy SSH public key to /home/deploy/.ssh/authorized_keys"
|
||||||
|
echo " 2. Log into the Gitea Docker registry: docker login git.timothykim.net"
|
||||||
|
echo " 3. Configure Nginx Proxy Manager at http://<server-ip>:81"
|
||||||
|
echo " 4. Restore NPM data/certs backup if migrating"
|
||||||
|
|
||||||
Reference in New Issue
Block a user