Skip to content

Commit 29bdb53

Browse files
committed
Initial commit
0 parents  commit 29bdb53

File tree

95 files changed

+10256
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+10256
-0
lines changed

.deploy/docker-compose-template.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: "3.9"
2+
services:
3+
${APP_NAME}:
4+
image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION}
5+
restart: always
6+
network_mode: bridge
7+
ports:
8+
- "80"
9+
environment:
10+
VIRTUAL_HOST: ${HOST_DOMAIN}
11+
LETSENCRYPT_HOST: ${HOST_DOMAIN}
12+
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
13+
volumes:
14+
- ${APP_NAME}-mydb:/app/App_Data
15+
${APP_NAME}-migration:
16+
image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION}
17+
restart: "no"
18+
profiles:
19+
- migration
20+
command: --AppTasks=migrate
21+
volumes:
22+
- ${APP_NAME}-mydb:/app/App_Data
23+
24+
volumes:
25+
${APP_NAME}-mydb:

.deploy/nginx-proxy-compose.yml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
version: '2'
2+
3+
services:
4+
nginx-proxy:
5+
image: jwilder/nginx-proxy
6+
container_name: nginx-proxy
7+
restart: always
8+
ports:
9+
- "80:80"
10+
- "443:443"
11+
volumes:
12+
- conf:/etc/nginx/conf.d
13+
- vhost:/etc/nginx/vhost.d
14+
- html:/usr/share/nginx/html
15+
- dhparam:/etc/nginx/dhparam
16+
- certs:/etc/nginx/certs:ro
17+
- /var/run/docker.sock:/tmp/docker.sock:ro
18+
network_mode: bridge
19+
20+
letsencrypt:
21+
image: jrcs/letsencrypt-nginx-proxy-companion:2.0
22+
container_name: nginx-proxy-le
23+
restart: always
24+
environment:
25+
26+
volumes_from:
27+
- nginx-proxy
28+
volumes:
29+
- certs:/etc/nginx/certs:rw
30+
- acme:/etc/acme.sh
31+
- /var/run/docker.sock:/var/run/docker.sock:ro
32+
network_mode: bridge
33+
34+
volumes:
35+
conf:
36+
vhost:
37+
html:
38+
dhparam:
39+
certs:
40+
acme:

.github/workflows/README.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# ServiceStack mix GitHub Actions
2+
`release.yml` generated from `x mix release-ghr-vanilla`, this template in designed to help with CI deployment to a dedicated server with SSH access.
3+
4+
## Overview
5+
`release.yml` is designed to work with a ServiceStack app deploying directly to a single server via SSH. A docker image is built and stored on GitHub's `ghcr.io` docker registry when a GitHub Release is created.
6+
7+
GitHub Actions specified in `release.yml` then copy files remotely via scp and use `docker-compose` to run the app remotely via SSH.
8+
9+
## Deployment server setup
10+
To get this working, a server needs to be setup with the following:
11+
12+
- SSH access
13+
- docker
14+
- docker-compose
15+
- ports 443 and 80 for web access of your hosted application
16+
17+
This can be your own server or any cloud hosted server like Digital Ocean, AWS, Azure etc.
18+
19+
When setting up your server, you'll want to use a dedicated SSH key for access to be used by GitHub Actions. GitHub Actions will need the *private* SSH key within a GitHub Secret to authenticate. This can be done via ssh-keygen and copying the public key to the authorized clients on the server.
20+
21+
To let your server handle multiple ServiceStack applications and automate the generation and management of TLS certificates, an additional docker-compose file is provided via the `x mix` template, `nginx-proxy-compose.yml`. This docker-compose file is ready to run and can be copied to the deployment server.
22+
23+
For example, once copied to remote `~/nginx-proxy-compose.yml`, the following command can be run on the remote server.
24+
25+
```
26+
docker-compose -f ~/nginx-proxy-compose.yml up -d
27+
```
28+
29+
This will run an nginx reverse proxy along with a companion container that will watch for additional containers in the same docker network and attempt to initialize them with valid TLS certificates.
30+
31+
## GitHub Repository setup
32+
The `release.yml` uses the following secrets.
33+
34+
- DEPLOY_HOST - hostname used to SSH to, this can either be an IP address or subdomain with A record pointing to the server.
35+
- DEPLOY_USERNAME - the username being logged into via SSH. Eg, `ubuntu`, `ec2-user`, `root` etc.
36+
- DEPLOY_KEY - SSH private key used to remotely access deploy server/app host.
37+
- LETSENCRYPT_EMAIL - Email address, required for Let's Encrypt automated TLS certificates.
38+
39+
These secrets can use the [GitHub CLI](https://cli.github.com/manual/gh_secret_set) for ease of creation. Eg, using the GitHub CLI the following can be set.
40+
41+
```bash
42+
gh secret set DEPLOY_HOST -b"<DEPLOY_HOST, domain or subdomain for your application and server host.>"
43+
gh secret set DEPLOY_USERNAME -b"<DEPLOY_USERNAME, the username being logged into via SSH. Eg, `ubuntu`, `ec2-user`, `root` etc.>"
44+
gh secret set DEPLOY_KEY -b"<DEPLOY_KEY, SSH private key used to remotely access deploy server/app host.>"
45+
gh secret set LETSENCRYPT_EMAIL -b"<LETSENCRYPT_EMAIL, Email address for your TLS certificate generation, eg [email protected]>"
46+
```
47+
48+
These secrets are used to populate variables within GitHub Actions and other configuration files.
49+
50+
## What's the process of `release.yml`?
51+
52+
![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/mix/release-ghr-vanilla-diagram.png)

.github/workflows/build.yml

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Build
2+
3+
on:
4+
pull_request: {}
5+
push:
6+
branches:
7+
- '**' # matches every branch
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-20.04
12+
steps:
13+
- name: checkout
14+
uses: actions/[email protected]
15+
16+
- name: setup .net core
17+
uses: actions/setup-dotnet@v3
18+
with:
19+
dotnet-version: '6.0'
20+
21+
- name: build
22+
run: dotnet build
23+
working-directory: .
24+
25+
- name: test
26+
run: |
27+
dotnet test
28+
if [ $? -eq 0 ]; then
29+
echo TESTS PASSED
30+
else
31+
echo TESTS FAILED
32+
exit 1
33+
fi
34+
working-directory: ./ExampleOpenAiPlugin.Tests
35+

.github/workflows/release.yml

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
name: Release
2+
permissions:
3+
packages: write
4+
contents: write
5+
on:
6+
# Triggered on new GitHub Release
7+
release:
8+
types: [published]
9+
# Triggered on every successful Build action
10+
workflow_run:
11+
workflows: ["Build"]
12+
branches: [main,master]
13+
types:
14+
- completed
15+
# Manual trigger for rollback to specific release or redeploy latest
16+
workflow_dispatch:
17+
inputs:
18+
version:
19+
default: latest
20+
description: Tag you want to release.
21+
required: true
22+
23+
jobs:
24+
push_to_registry:
25+
runs-on: ubuntu-22.04
26+
if: ${{ github.event.workflow_run.conclusion != 'failure' }}
27+
steps:
28+
# Checkout latest or specific tag
29+
- name: checkout
30+
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
31+
uses: actions/checkout@v3
32+
- name: checkout tag
33+
if: ${{ github.event.inputs.version != '' && github.event.inputs.version != 'latest' }}
34+
uses: actions/checkout@v3
35+
with:
36+
ref: refs/tags/${{ github.event.inputs.version }}
37+
38+
# Assign environment variables used in subsequent steps
39+
- name: Env variable assignment
40+
run: echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
41+
# TAG_NAME defaults to 'latest' if not a release or manual deployment
42+
- name: Assign version
43+
run: |
44+
echo "TAG_NAME=latest" >> $GITHUB_ENV
45+
if [ "${{ github.event.release.tag_name }}" != "" ]; then
46+
echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
47+
fi;
48+
if [ "${{ github.event.inputs.version }}" != "" ]; then
49+
echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
50+
fi;
51+
52+
- name: Setup node
53+
uses: actions/setup-node@v3
54+
with:
55+
node-version: 18
56+
# Run postinstall script
57+
- name: Install and build npm
58+
run: |
59+
npm install
60+
working-directory: ./ExampleOpenAiPlugin
61+
62+
# Publish .NET Project
63+
- name: Publish dotnet project
64+
working-directory: ./ExampleOpenAiPlugin
65+
run: |
66+
dotnet publish -c Release /p:APP_TASKS=prerender
67+
68+
# Authenticate, build and push to GitHub Container Registry (ghcr.io)
69+
- name: Login to GitHub Container Registry
70+
uses: docker/login-action@v2
71+
with:
72+
registry: ghcr.io
73+
username: ${{ github.actor }}
74+
password: ${{ secrets.GITHUB_TOKEN }}
75+
76+
# Build and push new docker image, skip for manual redeploy other than 'latest'
77+
- name: Build and push Docker images
78+
uses: docker/build-push-action@v3
79+
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
80+
with:
81+
file: Dockerfile
82+
context: .
83+
push: true
84+
tags: ghcr.io/${{ env.image_repository_name }}:${{ env.TAG_NAME }}
85+
86+
deploy_via_ssh:
87+
needs: push_to_registry
88+
runs-on: ubuntu-22.04
89+
if: ${{ github.event.workflow_run.conclusion != 'failure' }}
90+
steps:
91+
# Checkout latest or specific tag
92+
- name: checkout
93+
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
94+
uses: actions/checkout@v3
95+
- name: checkout tag
96+
if: ${{ github.event.inputs.version != '' && github.event.inputs.version != 'latest' }}
97+
uses: actions/checkout@v3
98+
with:
99+
ref: refs/tags/${{ github.event.inputs.version }}
100+
101+
- name: repository name fix and env
102+
run: |
103+
echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
104+
echo "domain=${{ secrets.DEPLOY_HOST }}" >> $GITHUB_ENV
105+
echo "letsencrypt_email=${{ secrets.LETSENCRYPT_EMAIL }}" >> $GITHUB_ENV
106+
echo "TAG_NAME=latest" >> $GITHUB_ENV
107+
if [ "${{ github.event.release.tag_name }}" != "" ]; then
108+
echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
109+
fi;
110+
if [ "${{ github.event.inputs.version }}" != "" ]; then
111+
echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
112+
fi;
113+
114+
# Populate docker-compose.yml with variables from build process, including TAG_NAME.
115+
- name: docker-compose file prep
116+
uses: danielr1996/[email protected]
117+
env:
118+
RELEASE_VERSION: ${{ env.TAG_NAME }}
119+
IMAGE_REPO: ${{ env.image_repository_name }}
120+
APP_NAME: ${{ github.event.repository.name }}
121+
HOST_DOMAIN: ${{ secrets.DEPLOY_HOST }}
122+
LETSENCRYPT_EMAIL: ${{ env.letsencrypt_email }}
123+
with:
124+
input: .deploy/docker-compose-template.yml
125+
output: .deploy/${{ github.event.repository.name }}-docker-compose.yml
126+
127+
# Copy only the docker-compose.yml to remote server home folder
128+
- name: copy compose file via scp
129+
uses: appleboy/[email protected]
130+
with:
131+
host: ${{ secrets.DEPLOY_HOST }}
132+
username: ${{ secrets.DEPLOY_USERNAME }}
133+
port: 22
134+
key: ${{ secrets.DEPLOY_KEY }}
135+
source: ".deploy/${{ github.event.repository.name }}-docker-compose.yml"
136+
target: "~/"
137+
138+
- name: Run remote db migrations
139+
uses: appleboy/[email protected]
140+
env:
141+
APPTOKEN: ${{ secrets.GITHUB_TOKEN }}
142+
USERNAME: ${{ secrets.DEPLOY_USERNAME }}
143+
with:
144+
host: ${{ secrets.DEPLOY_HOST }}
145+
username: ${{ secrets.DEPLOY_USERNAME }}
146+
key: ${{ secrets.DEPLOY_KEY }}
147+
port: 22
148+
envs: APPTOKEN,USERNAME
149+
script: |
150+
echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin
151+
docker compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml pull
152+
docker compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml up ${{ github.event.repository.name }}-migration --exit-code-from ${{ github.event.repository.name }}-migration
153+
154+
# Deploy Docker image with ServiceStack application using `docker compose up` remotely
155+
- name: remote docker-compose up via ssh
156+
uses: appleboy/[email protected]
157+
env:
158+
APPTOKEN: ${{ secrets.GITHUB_TOKEN }}
159+
USERNAME: ${{ secrets.DEPLOY_USERNAME }}
160+
with:
161+
host: ${{ secrets.DEPLOY_HOST }}
162+
username: ${{ secrets.DEPLOY_USERNAME }}
163+
key: ${{ secrets.DEPLOY_KEY }}
164+
port: 22
165+
envs: APPTOKEN,USERNAME
166+
script: |
167+
echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin
168+
docker-compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml pull
169+
docker-compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml up -d

0 commit comments

Comments
 (0)