# Forgejo - Self-hosted DevOps Stack # Deploys to: 'devops' role (see deployments/hosts/roles.yaml) # Docs: https://forgejo.org/docs/latest/admin/ # # Deployment: # ./deployments/scripts/deploy-devops-stack.sh # # Manual usage (resolves host from role): # TARGET=$(source lib/hosts.sh && get_role_host devops) # scp -r deployments/docker/forgejo $TARGET:/bigdisk/forgejo/ # ssh $TARGET "cd /bigdisk/forgejo && docker-compose up -d" # # SSL Certificates (self-signed, VPN-only): # mkdir -p ssl && cd ssl # # forge.nasty.sh # openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ # -keyout forge.nasty.sh.key -out forge.nasty.sh.crt \ # -subj '/CN=forge.nasty.sh' -addext 'subjectAltName=DNS:forge.nasty.sh' # # npm.nasty.sh (Verdaccio) # openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ # -keyout npm.nasty.sh.key -out npm.nasty.sh.crt \ # -subj '/CN=npm.nasty.sh' -addext 'subjectAltName=DNS:npm.nasty.sh' # # Access (VPN-only, add to /etc/hosts with IP from roles.yaml): # forge.nasty.sh npm.nasty.sh # # Features: # - Git repositories (Forgejo) # - NPM/PyPI/Container registries (Forgejo) # - Forgejo Actions (built-in CI) # - Verdaccio NPM cache (npm.nasty.sh) services: nginx: image: nginx:alpine container_name: forgejo-nginx restart: unless-stopped ports: - "80:80" - "443:443" - "2222:2222" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro networks: - forgejo depends_on: - forgejo forgejo: image: codeberg.org/forgejo/forgejo:11 container_name: forgejo environment: - USER_UID=1000 - USER_GID=1000 # Database - FORGEJO__database__DB_TYPE=postgres - FORGEJO__database__HOST=db:5432 - FORGEJO__database__NAME=forgejo - FORGEJO__database__USER=forgejo - FORGEJO__database__PASSWD=${FORGEJO_DB_PASSWORD} # Server - FORGEJO__server__DOMAIN=forge.black.local - FORGEJO__server__SSH_DOMAIN=forge.black.local - FORGEJO__server__ROOT_URL=http://forge.black.local/ - FORGEJO__server__SSH_PORT=2222 - FORGEJO__server__SSH_LISTEN_PORT=22 - FORGEJO__server__LFS_START_SERVER=true # Security - FORGEJO__security__INSTALL_LOCK=true - FORGEJO__security__SECRET_KEY=${FORGEJO_SECRET_KEY} - FORGEJO__security__INTERNAL_TOKEN=${FORGEJO_INTERNAL_TOKEN} # Service settings - FORGEJO__service__DISABLE_REGISTRATION=true - FORGEJO__service__REQUIRE_SIGNIN_VIEW=false - FORGEJO__service__DEFAULT_KEEP_EMAIL_PRIVATE=true # Package registries - FORGEJO__packages__ENABLED=true # Actions (CI/CD) - FORGEJO__actions__ENABLED=true - FORGEJO__actions__DEFAULT_ACTIONS_URL=https://code.forgejo.org # OAuth2 JWT - FORGEJO__oauth2__JWT_SECRET=${FORGEJO_JWT_SECRET} restart: unless-stopped networks: - forgejo volumes: - ./data/forgejo:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro expose: - "3000" - "22" depends_on: db: condition: service_healthy db: image: postgres:16-alpine container_name: forgejo-db restart: unless-stopped environment: - POSTGRES_USER=forgejo - POSTGRES_PASSWORD=${FORGEJO_DB_PASSWORD} - POSTGRES_DB=forgejo networks: - forgejo volumes: - ./data/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD", "pg_isready", "-U", "forgejo"] interval: 10s timeout: 5s retries: 5 runner: image: code.forgejo.org/forgejo/runner:6.2.1 container_name: forgejo-runner command: forgejo-runner daemon restart: unless-stopped depends_on: - forgejo # Get docker GID with: ssh "getent group docker | cut -d: -f3" # HOST-SPECIFIC: Update this GID when migrating to new host group_add: - "${DOCKER_GID:-1001}" volumes: - ./data/runner:/data - /var/run/docker.sock:/var/run/docker.sock networks: - forgejo # Runner registration: # docker exec -u git forgejo forgejo actions generate-runner-token # docker run --rm -v ./data/runner:/data code.forgejo.org/forgejo/runner:6.2.1 \ # forgejo-runner register --instance http://localhost:3000 --token --name $(hostname)-runner --no-interactive # ========================================================================== # pypiserver - Python Package Index (proxied via nginx at pypi.black.local) # ========================================================================== pypi: image: pypiserver/pypiserver:latest container_name: pypiserver restart: unless-stopped command: run -P . -a . --server wsgiref volumes: - /bigdisk/pypi/packages:/data/packages expose: - "8080" networks: - forgejo healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:8080/"] interval: 30s timeout: 10s retries: 3 # ========================================================================== # Verdaccio - NPM Cache (proxied via nginx at npm.black.local) # ========================================================================== verdaccio: image: verdaccio/verdaccio:6 container_name: verdaccio restart: unless-stopped environment: - VERDACCIO_PORT=4873 - VERDACCIO_PUBLIC_URL=http://npm.black.local - FORGEJO_NPM_TOKEN=${FORGEJO_NPM_TOKEN} expose: - "4873" volumes: - /bigdisk/verdaccio/storage:/verdaccio/storage - /bigdisk/verdaccio/config:/verdaccio/conf networks: - forgejo healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:4873/-/ping"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: forgejo: driver: bridge