Files
gb-site/SERVER.md
Ivan Liashkevich d307a3fbad Initial project setup: Next.js frontend + .NET 9 backend
- Frontend: Next.js 16 + shadcn/ui + Tailwind CSS 4
- Backend: .NET 9 Web API with Npgsql health check
- Docker Compose for prod and dev environments
- Woodpecker CI pipeline for auto-deploy
- Health check endpoints for E2E testing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:39:37 +02:00

10 KiB

GoodBrick Server Infrastructure

SSH Access

  • Host: 31.131.18.254
  • User: deploy
  • Auth: SSH key (already configured, no password needed)
  • Command: ssh deploy@31.131.18.254

Server Structure

Base Directory: /srv

/srv/
├── apps/           # Empty, ready for applications
├── gitea/          # Git server
├── postgres/       # PostgreSQL database
├── proxy/          # Caddy reverse proxy
├── uptime-kuma/    # Status monitoring
└── woodpecker/     # CI/CD server

Docker Network

  • Network name: app-network (external, shared)
  • All services connected to this network
  • Containers communicate by name (e.g., postgres, gitea, caddy)

Live Services

Production URLs

All domains point to 31.131.18.254 via A records.


Service Details

1. Caddy (Reverse Proxy)

  • Location: /srv/proxy
  • Container: caddy
  • Image: caddy:2
  • Ports: 80, 443 (public)
  • Config: /srv/proxy/Caddyfile
  • SSL: Automatic via Let's Encrypt

Caddyfile Routes

git.goodbrick.com.ua {
  reverse_proxy gitea:3000
}

status.goodbrick.com.ua {
  reverse_proxy uptime-kuma:3001
}

ci.goodbrick.com.ua {
  reverse_proxy woodpecker-server:8000 {
    flush_interval -1  # For SSE support
  }
}

new.goodbrick.com.ua {
  reverse_proxy new:3000
}

dev.goodbrick.com.ua {
  reverse_proxy dev:3000
}

Important Notes:

  • Use container names (not 127.0.0.1 or localhost)
  • flush_interval -1 required for Woodpecker's Server-Sent Events

Restart:

ssh deploy@31.131.18.254 'cd /srv/proxy && docker compose restart'

2. PostgreSQL

  • Location: /srv/postgres
  • Container: postgres
  • Image: postgres:16
  • Port: 127.0.0.1:5432 (localhost only)
  • Data: /srv/postgres/data
  • Credentials: /srv/postgres/CREDENTIALS.txt (chmod 600)

Master Admin

Host: postgres:5432 (from containers) or 127.0.0.1:5432 (from host)
User: app
Password: zYWT5JWu3iAbbW7mOyd1
Database: app

Application Databases

Gitea:

User: gitea_user
Password: gitea_pass_zYWT5JWu3iAbbW7m
Database: gitea_db
Connection String: postgres://gitea_user:gitea_pass_zYWT5JWu3iAbbW7m@postgres:5432/gitea_db

Production App:

User: prod_user
Password: prod_pass_kL9mN2pQ7xR8sT4v
Database: prod_db
Connection String: postgres://prod_user:prod_pass_kL9mN2pQ7xR8sT4v@postgres:5432/prod_db

Development App:

User: dev_user
Password: dev_pass_vB6nM3qP8yW2rT9k
Database: dev_db
Connection String: postgres://dev_user:dev_pass_vB6nM3qP8yW2rT9k@postgres:5432/dev_db

Important:

  • Each app has its own isolated database and user
  • Users cannot access other databases
  • PostgreSQL only accessible via Docker network

Restart:

ssh deploy@31.131.18.254 'cd /srv/postgres && docker compose restart'

3. Gitea (Git Server)

  • Location: /srv/gitea
  • Container: gitea
  • Image: gitea/gitea:latest
  • URL: https://git.goodbrick.com.ua
  • Admin: admin (set during installation)
  • Ports:
    • 127.0.0.1:3002:3000 (HTTP)
    • 127.0.0.1:2222:22 (SSH)
  • Database: gitea_db (PostgreSQL)
  • Data: /srv/gitea/data

OAuth Application for Woodpecker

Config:

environment:
  - GITEA__server__DOMAIN=git.goodbrick.com.ua
  - GITEA__server__ROOT_URL=https://git.goodbrick.com.ua/
  - GITEA__webhook__ALLOWED_HOST_LIST=*  # Allows webhooks to Woodpecker
  - GITEA__database__DB_TYPE=postgres
  - GITEA__database__HOST=postgres:5432
  - GITEA__database__NAME=gitea_db
  - GITEA__database__USER=gitea_user

Restart:

ssh deploy@31.131.18.254 'cd /srv/gitea && docker compose restart'

4. Uptime Kuma (Monitoring)

  • Location: /srv/uptime-kuma
  • Container: uptime-kuma
  • Image: louislam/uptime-kuma:2
  • URL: https://status.goodbrick.com.ua
  • Port: 127.0.0.1:3001:3001
  • Data: /srv/uptime-kuma/data

Restart:

ssh deploy@31.131.18.254 'cd /srv/uptime-kuma && docker compose restart'

5. Woodpecker CI

  • Location: /srv/woodpecker
  • Containers: woodpecker-server, woodpecker-agent
  • Image: woodpeckerci/woodpecker-server:latest (v2.8.3), woodpeckerci/woodpecker-agent:latest
  • URL: https://ci.goodbrick.com.ua
  • Port: 127.0.0.1:8000:8000
  • Data: /srv/woodpecker/data

Config:

environment:
  # Server
  - WOODPECKER_OPEN=true
  - WOODPECKER_HOST=https://ci.goodbrick.com.ua
  - WOODPECKER_GITEA=true
  - WOODPECKER_GITEA_URL=https://git.goodbrick.com.ua
  - WOODPECKER_GITEA_CLIENT=157422cf-7391-4fb0-8f2d-27083676dda6
  - WOODPECKER_GITEA_SECRET=gto_2r3udrnmvtebt37v35bzl375eq5bumxqu2dpwwdfflbumnp5fy7q
  - WOODPECKER_AGENT_SECRET=supersecrettoken123
  - WOODPECKER_ADMIN=admin

  # Agent
  - WOODPECKER_SERVER=woodpecker-server:9000
  - WOODPECKER_AGENT_SECRET=supersecrettoken123

Status: Working! Login with Gitea account.

Important Notes:

  • Uses OAuth authentication via Gitea
  • Agent connects to server on port 9000 (gRPC)
  • Agent has access to Docker socket for running builds
  • Version 2.8.3 fixes JavaScript security issues (v2.7.2 had SES errors)

Restart:

ssh deploy@31.131.18.254 'cd /srv/woodpecker && docker compose restart'

Common Commands

View all containers

ssh deploy@31.131.18.254 'docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'

View container logs

ssh deploy@31.131.18.254 'docker logs <container_name> --tail 50'
ssh deploy@31.131.18.254 'docker logs <container_name> -f'  # Follow logs

Restart a service

ssh deploy@31.131.18.254 'cd /srv/<service> && docker compose restart'

Restart all services

ssh deploy@31.131.18.254 'cd /srv/postgres && docker compose restart && \
  cd /srv/gitea && docker compose restart && \
  cd /srv/uptime-kuma && docker compose restart && \
  cd /srv/woodpecker && docker compose restart && \
  cd /srv/proxy && docker compose restart'

Access PostgreSQL CLI

ssh deploy@31.131.18.254 'docker exec -it postgres psql -U app -d app'

Check Docker network

ssh deploy@31.131.18.254 'docker network inspect app-network'
ssh deploy@31.131.18.254 'docker ps --format "{{.Names}}\t{{.Networks}}"'

Test container connectivity

ssh deploy@31.131.18.254 'docker exec <container1> ping -c 2 <container2>'

Troubleshooting

Issue: Container can't reach another container

Symptoms: "connection refused", "no such host"

Check:

# Verify all containers are in app-network
ssh deploy@31.131.18.254 'docker ps --format "{{.Names}}\t{{.Networks}}"'

Solution:

  1. Ensure all docker-compose.yml files have:
networks:
  app-network:
    external: true
  1. Restart the affected service

Issue: "dial tcp: lookup on 127.0.0.11:53: no such host"

Cause: Container not in app-network

Solution:

ssh deploy@31.131.18.254 'cd /srv/<service> && docker compose down && docker compose up -d'

Issue: Caddy shows "502 Bad Gateway"

Causes:

  1. Target service is down
  2. Target service not in app-network
  3. Wrong port/container name in Caddyfile

Check:

# Check if target is running
ssh deploy@31.131.18.254 'docker ps | grep <service>'

# Check Caddy logs
ssh deploy@31.131.18.254 'docker logs caddy --tail 50'

# Test direct connection
ssh deploy@31.131.18.254 'docker exec caddy wget -O- http://<container>:<port>'

Issue: Woodpecker shows blank page or JavaScript errors

Symptoms: "SES Removing unpermitted intrinsics", SyntaxError

Solution:

  1. Update to latest version (2.8.3+)
  2. Ensure Caddy has flush_interval -1 for SSE support
  3. Clear browser cache (Ctrl+Shift+R)

Issue: SSL certificate not working

Cause: Usually DNS propagation or Let's Encrypt rate limits

Check:

# Check Caddy logs
ssh deploy@31.131.18.254 'docker logs caddy | grep -i certificate'

# Check if domain resolves
nslookup <domain>

Solution: Wait for DNS propagation (up to 24h) or check DNS A records.


Security Notes

  1. PostgreSQL:

    • Not exposed to internet (127.0.0.1 only)
    • Separate users for each application
    • Credentials stored in /srv/postgres/CREDENTIALS.txt (chmod 600)
  2. SSH:

    • Key-based authentication only
    • User deploy has Docker permissions
  3. Docker Network:

    • All containers isolated in app-network
    • No direct internet access except through Caddy
  4. Secrets:

    • Never commit credentials to git
    • Store sensitive data in environment variables
    • Use .env files (gitignored)

Next Steps / TODO

  • Deploy production app to new.goodbrick.com.ua (port 3100)
  • Deploy development app to dev.goodbrick.com.ua (port 3200)
  • Set up email for Gitea (optional)
  • Configure Woodpecker pipelines for repositories
  • Set up automatic backups for PostgreSQL databases
  • Configure monitoring alerts in Uptime Kuma

File Locations Summary

Server (31.131.18.254):
├── /srv/
│   ├── apps/
│   ├── gitea/
│   │   ├── docker-compose.yml
│   │   └── data/
│   ├── postgres/
│   │   ├── docker-compose.yml
│   │   ├── data/
│   │   └── CREDENTIALS.txt ← All DB credentials
│   ├── proxy/
│   │   ├── docker-compose.yml
│   │   ├── Caddyfile ← All routes
│   │   ├── data/
│   │   └── config/
│   ├── uptime-kuma/
│   │   ├── docker-compose.yml
│   │   └── data/
│   └── woodpecker/
│       ├── docker-compose.yml
│       └── data/

Local:
└── C:\Work\goodbrick\GBSite\
    ├── SERVER.md ← This file
    └── README.md ← Project overview

Last Updated: 2026-02-09 Maintained by: Claude AI Assistant