Repository: owncloud/ocis
Pull request #10163 (2024-09-25 11:21:56)

Bugfix: Improve Ready and Health Checks
## Description

- Fixed the issue where ready and health checks were not functioning correctly.
- Enhanced the checks to verify the readiness and health of individual services by evaluating their specific requirements.

## Service Probes

Checklist moved to #10281 

## Questions

- how to handle services that do not have a http endpoint

## Related Issue
- Fixes https://github.com/owncloud/ocis/issues/8783

## Motivation and Context
health and ready checks are essential to find out if a service is ready to serve requests. In the past, the checks were not functioning correctly. This release fixes the issue and enhances the checks to verify the readiness and health of individual services by evaluating their specific requirements.

## How Has This Been Tested?
- unit tests
- local instance

## Types of changes
- [X] Bug fix (non-breaking change which fixes an issue)
- [X] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [X] Technical debt
- [ ] Tests only (no source changes)

## Checklist:
- [X] Code changes
- [X] Unit tests added
- [ ] Acceptance tests added
- [ ] Documentation ticket raised: <link> 


update-docs[bot]: Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would create a [changelog](https://github.com/owncloud/ocis/blob/master/changelog/README.md) item based on your changes.

sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [56.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [2 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


butonic: related: https://github.com/owncloud/ocis/issues/6774
sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [60.1% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [2 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [62.9% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [3 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [58.6% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [3 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [56.4% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


dragonchaser: We decided to split the issue into several PRs, this PR only contains 3 service healthchecks and basic skeletons & refactoring, the others will be implemented in follow-up PRs. (List see #10281 )
sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [4 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [6 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [2 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.5% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [76.3% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [2 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [75.7% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10163&metric=new_duplicated_lines_density&view=list) (required ≤ 50%)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10163)



Patch:
diff --git a/ocis-pkg/handlers/checker.go b/ocis-pkg/handlers/checker.go
new file mode 100644
index 00000000000..de87bd7f384
--- /dev/null
+++ b/ocis-pkg/handlers/checker.go
@@ -0,0 +1,117 @@
+package handlers
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"maps"
+	"net/http"
+
+	"golang.org/x/sync/errgroup"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+)
+
+// check is a function that performs a check.
+type check func(ctx context.Context) error
+
+// CheckHandlerConfiguration defines the configuration for the CheckHandler.
+type CheckHandlerConfiguration struct {
+	logger        log.Logger
+	checks        map[string]check
+	limit         int
+	statusFailed  int
+	statusSuccess int
+}
+
+// NewCheckHandlerConfiguration initializes a new CheckHandlerConfiguration.
+func NewCheckHandlerConfiguration() CheckHandlerConfiguration {
+	return CheckHandlerConfiguration{
+		checks:        make(map[string]check),
+		limit:         -1,
+		statusFailed:  http.StatusInternalServerError,
+		statusSuccess: http.StatusOK,
+	}
+}
+
+// WithLogger sets the logger for the CheckHandlerConfiguration.
+func (c CheckHandlerConfiguration) WithLogger(l log.Logger) CheckHandlerConfiguration {
+	c.logger = l
+	return c
+}
+
+// WithCheck sets a check for the CheckHandlerConfiguration.
+func (c CheckHandlerConfiguration) WithCheck(name string, f check) CheckHandlerConfiguration {
+	if _, ok := c.checks[name]; ok {
+		c.logger.Panic().Str("check", name).Msg("check already exists")
+	}
+
+	c.checks[name] = f
+	return c
+}
+
+// WithLimit limits the number of active goroutines for the checks to at most n
+func (c CheckHandlerConfiguration) WithLimit(n int) CheckHandlerConfiguration {
+	c.limit = n
+	return c
+}
+
+// WithStatusFailed sets the status code for the failed checks.
+func (c CheckHandlerConfiguration) WithStatusFailed(status int) CheckHandlerConfiguration {
+	c.statusFailed = status
+	return c
+}
+
+// WithStatusSuccess sets the status code for the successful checks.
+func (c CheckHandlerConfiguration) WithStatusSuccess(status int) CheckHandlerConfiguration {
+	c.statusSuccess = status
+	return c
+}
+
+// CheckHandler is a http Handler that performs different checks.
+type CheckHandler struct {
+	conf CheckHandlerConfiguration
+}
+
+// NewCheckHandler initializes a new CheckHandler.
+func NewCheckHandler(c CheckHandlerConfiguration) *CheckHandler {
+	c.checks = maps.Clone(c.checks) // prevent check duplication after initialization
+	return &CheckHandler{
+		conf: c,
+	}
+}
+
+// AddCheck adds a check to the CheckHandler.
+func (h *CheckHandler) AddCheck(name string, c check) {
+	h.conf.WithCheck(name, c)
+}
+
+func (h *CheckHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	g, ctx := errgroup.WithContext(r.Context())
+	g.SetLimit(h.conf.limit)
+
+	for name, check := range h.conf.checks {
+		checker := check
+		checkerName := name
+		g.Go(func() error { // https://go.dev/blog/loopvar-preview per iteration scope since go 1.22
+			if err := checker(ctx); err != nil { // since go 1.22 for loops have a per-iteration scope instead of per-loop scope, no need to pin the check...
+				return fmt.Errorf("'%s': %w", checkerName, err)
+			}
+
+			return nil
+		})
+	}
+
+	status := h.conf.statusSuccess
+	if err := g.Wait(); err != nil {
+		status = h.conf.statusFailed
+		h.conf.logger.Error().Err(err).Msg("check failed")
+	}
+
+	w.Header().Set("Content-Type", "text/plain")
+	w.WriteHeader(status)
+
+	if _, err := io.WriteString(w, http.StatusText(status)); err != nil { // io.WriteString should not fail, but if it does, we want to know.
+		h.conf.logger.Panic().Err(err).Msg("failed to write response")
+	}
+}
diff --git a/ocis-pkg/handlers/checknats.go b/ocis-pkg/handlers/checknats.go
new file mode 100644
index 00000000000..7eba98e9067
--- /dev/null
+++ b/ocis-pkg/handlers/checknats.go
@@ -0,0 +1,23 @@
+package handlers
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/nats-io/nats.go"
+)
+
+// NewNatsCheck checks the reachability of a nats server.
+func NewNatsCheck(natsCluster string, options ...nats.Option) func(context.Context) error {
+	return func(_ context.Context) error {
+		n, err := nats.Connect(natsCluster, options...)
+		if err != nil {
+			return fmt.Errorf("could not connect to nats server: %v", err)
+		}
+		defer n.Close()
+		if n.Status() != nats.CONNECTED {
+			return fmt.Errorf("nats server not connected")
+		}
+		return nil
+	}
+}
diff --git a/ocis-pkg/handlers/checktcp.go b/ocis-pkg/handlers/checktcp.go
new file mode 100644
index 00000000000..0db97bfabf8
--- /dev/null
+++ b/ocis-pkg/handlers/checktcp.go
@@ -0,0 +1,24 @@
+package handlers
+
+import (
+	"context"
+	"net"
+	"time"
+)
+
+// NewTCPCheck returns a check that connects to a given tcp endpoint.
+func NewTCPCheck(address string) func(ctx context.Context) error {
+	return func(_ context.Context) error {
+		conn, err := net.DialTimeout("tcp", address, 3*time.Second)
+		if err != nil {
+			return err
+		}
+
+		err = conn.Close()
+		if err != nil {
+			return err
+		}
+
+		return nil
+	}
+}
diff --git a/ocis-pkg/handlers/debughandlers.go b/ocis-pkg/handlers/debughandlers.go
deleted file mode 100644
index ebc6de781ec..00000000000
--- a/ocis-pkg/handlers/debughandlers.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package handlers
-
-import (
-	"io"
-	"net/http"
-)
-
-// Health can be used for a health endpoint
-func Health(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "text/plain")
-	w.WriteHeader(http.StatusOK)
-
-	// TODO: check if services are up and running
-
-	_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-	// io.WriteString should not fail but if it does, we want to know.
-	if err != nil {
-		panic(err)
-	}
-}
-
-// Ready can be used as a ready endpoint
-func Ready(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "text/plain")
-	w.WriteHeader(http.StatusOK)
-
-	// TODO: check if services are up and running
-
-	_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-	// io.WriteString should not fail but if it does, we want to know.
-	if err != nil {
-		panic(err)
-	}
-}
diff --git a/ocis-pkg/service/debug/option.go b/ocis-pkg/service/debug/option.go
index 5f9f593327f..3ed6b162f99 100644
--- a/ocis-pkg/service/debug/option.go
+++ b/ocis-pkg/service/debug/option.go
@@ -20,9 +20,9 @@ type Options struct {
 	Token                string
 	Pprof                bool
 	Zpages               bool
-	Health               func(http.ResponseWriter, *http.Request)
-	Ready                func(http.ResponseWriter, *http.Request)
-	ConfigDump           func(http.ResponseWriter, *http.Request)
+	Health               http.Handler
+	Ready                http.Handler
+	ConfigDump           http.Handler
 	CorsAllowedOrigins   []string
 	CorsAllowedMethods   []string
 	CorsAllowedHeaders   []string
@@ -97,21 +97,21 @@ func Zpages(z bool) Option {
 }
 
 // Health provides a function to set the health option.
-func Health(h func(http.ResponseWriter, *http.Request)) Option {
+func Health(h http.Handler) Option {
 	return func(o *Options) {
 		o.Health = h
 	}
 }
 
 // Ready provides a function to set the ready option.
-func Ready(r func(http.ResponseWriter, *http.Request)) Option {
+func Ready(r http.Handler) Option {
 	return func(o *Options) {
 		o.Ready = r
 	}
 }
 
 // ConfigDump to be documented.
-func ConfigDump(r func(http.ResponseWriter, *http.Request)) Option {
+func ConfigDump(r http.Handler) Option {
 	return func(o *Options) {
 		o.ConfigDump = r
 	}
diff --git a/ocis-pkg/service/debug/service.go b/ocis-pkg/service/debug/service.go
index 651856f42a9..82e056ea7d4 100644
--- a/ocis-pkg/service/debug/service.go
+++ b/ocis-pkg/service/debug/service.go
@@ -8,11 +8,12 @@ import (
 
 	chimiddleware "github.com/go-chi/chi/v5/middleware"
 	"github.com/justinas/alice"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+	"go.opentelemetry.io/contrib/zpages"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/cors"
 	"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
 	graphMiddleware "github.com/owncloud/ocis/v2/services/graph/pkg/middleware"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
-	"go.opentelemetry.io/contrib/zpages"
 )
 
 // NewService initializes a new debug service.
@@ -28,11 +29,16 @@ func NewService(opts ...Option) *http.Server {
 		promhttp.Handler(),
 	))
 
-	mux.HandleFunc("/healthz", dopts.Health)
-	mux.HandleFunc("/readyz", dopts.Ready)
+	if dopts.Health != nil {
+		mux.Handle("/healthz", dopts.Health)
+	}
+
+	if dopts.Ready != nil {
+		mux.Handle("/readyz", dopts.Ready)
+	}
 
 	if dopts.ConfigDump != nil {
-		mux.HandleFunc("/config", dopts.ConfigDump)
+		mux.Handle("/config", dopts.ConfigDump)
 	}
 
 	if dopts.Pprof {
diff --git a/ocis-pkg/shared/healthchecklist.go b/ocis-pkg/shared/healthchecklist.go
deleted file mode 100644
index ce240d7ed38..00000000000
--- a/ocis-pkg/shared/healthchecklist.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package shared
-
-import "net"
-
-// Check is a single health-check
-type Check func() error
-
-// RunChecklist runs all the given checks
-func RunChecklist(checks ...Check) error {
-	for _, c := range checks {
-		err := c()
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// TCPConnect connects to a given tcp endpoint
-func TCPConnect(host string) Check {
-	return func() error {
-		conn, err := net.Dial("tcp", host)
-		if err != nil {
-			return err
-		}
-		defer conn.Close()
-		return nil
-	}
-}
diff --git a/services/activitylog/pkg/command/server.go b/services/activitylog/pkg/command/server.go
index 96601df47eb..9c018ecdbcd 100644
--- a/services/activitylog/pkg/command/server.go
+++ b/services/activitylog/pkg/command/server.go
@@ -9,10 +9,11 @@ import (
 	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
 	"github.com/cs3org/reva/v2/pkg/store"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+	microstore "go-micro.dev/v4/store"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/registry"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
@@ -22,9 +23,8 @@ import (
 	"github.com/owncloud/ocis/v2/services/activitylog/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/activitylog/pkg/logging"
 	"github.com/owncloud/ocis/v2/services/activitylog/pkg/metrics"
+	"github.com/owncloud/ocis/v2/services/activitylog/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/activitylog/pkg/server/http"
-	"github.com/urfave/cli/v2"
-	microstore "go-micro.dev/v4/store"
 )
 
 var _registeredEvents = []events.Unmarshaller{
@@ -120,7 +120,6 @@ func Server(cfg *config.Config) *cli.Command {
 					http.Context(ctx), // NOTE: not passing this "option" leads to a panic in go-micro
 					http.TraceProvider(tracerProvider),
 					http.Stream(evStream),
-					http.RegisteredEvents(_registeredEvents),
 					http.Store(evStore),
 					http.GatewaySelector(gatewaySelector),
 					http.HistoryClient(hClient),
@@ -146,20 +145,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/activitylog/pkg/server/debug/option.go b/services/activitylog/pkg/server/debug/option.go
new file mode 100644
index 00000000000..3d499becf5f
--- /dev/null
+++ b/services/activitylog/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/activitylog/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/activitylog/pkg/server/debug/server.go b/services/activitylog/pkg/server/debug/server.go
new file mode 100644
index 00000000000..09218a407bd
--- /dev/null
+++ b/services/activitylog/pkg/server/debug/server.go
@@ -0,0 +1,37 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	healthHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	readyHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger).
+			WithCheck("nats reachability", handlers.NewNatsCheck(options.Config.Events.Cluster)),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(healthHandler),
+		debug.Ready(readyHandler),
+	), nil
+}
diff --git a/services/antivirus/pkg/command/server.go b/services/antivirus/pkg/command/server.go
index 0acbd873212..d259f0f5e60 100644
--- a/services/antivirus/pkg/command/server.go
+++ b/services/antivirus/pkg/command/server.go
@@ -5,16 +5,15 @@ import (
 	"fmt"
 
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/antivirus/pkg/config"
 	"github.com/owncloud/ocis/v2/services/antivirus/pkg/config/parser"
+	"github.com/owncloud/ocis/v2/services/antivirus/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/antivirus/pkg/service"
-	"github.com/urfave/cli/v2"
 )
 
 // Server is the entrypoint for the server command.
@@ -55,20 +54,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/antivirus/pkg/server/debug/option.go b/services/antivirus/pkg/server/debug/option.go
new file mode 100644
index 00000000000..1118208c8e1
--- /dev/null
+++ b/services/antivirus/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/antivirus/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/antivirus/pkg/server/debug/server.go b/services/antivirus/pkg/server/debug/server.go
new file mode 100644
index 00000000000..73009607de3
--- /dev/null
+++ b/services/antivirus/pkg/server/debug/server.go
@@ -0,0 +1,51 @@
+package debug
+
+import (
+	"context"
+	"errors"
+	"net/http"
+
+	"github.com/dutchcoders/go-clamd"
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	healthHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	readyHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger).
+			WithCheck("nats reachability", handlers.NewNatsCheck(options.Config.Events.Cluster)).
+			WithCheck("antivirus reachability", func(ctx context.Context) error {
+				cfg := options.Config
+				switch cfg.Scanner.Type {
+				default:
+					return errors.New("no antivirus configured")
+				case "clamav":
+					return clamd.NewClamd(cfg.Scanner.ClamAV.Socket).Ping()
+				case "icap":
+					return handlers.NewTCPCheck(cfg.Scanner.ICAP.URL)(ctx)
+				}
+			}),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(healthHandler),
+		debug.Ready(readyHandler),
+	), nil
+}
diff --git a/services/app-provider/pkg/server/debug/server.go b/services/app-provider/pkg/server/debug/server.go
index 598a8e2f5ea..46264bd66b9 100644
--- a/services/app-provider/pkg/server/debug/server.go
+++ b/services/app-provider/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/app-provider/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/app-registry/pkg/command/server.go b/services/app-registry/pkg/command/server.go
index 0a85ce0346a..b37f29a7689 100644
--- a/services/app-registry/pkg/command/server.go
+++ b/services/app-registry/pkg/command/server.go
@@ -73,6 +73,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/app-registry/pkg/server/debug/server.go b/services/app-registry/pkg/server/debug/server.go
index e85c77274f9..46264bd66b9 100644
--- a/services/app-registry/pkg/server/debug/server.go
+++ b/services/app-registry/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/app-registry/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/audit/pkg/command/server.go b/services/audit/pkg/command/server.go
index 93f945e4976..84bf206bc9d 100644
--- a/services/audit/pkg/command/server.go
+++ b/services/audit/pkg/command/server.go
@@ -7,16 +7,15 @@ import (
 	"github.com/cs3org/reva/v2/pkg/events"
 	"github.com/cs3org/reva/v2/pkg/events/stream"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/audit/pkg/config"
 	"github.com/owncloud/ocis/v2/services/audit/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/audit/pkg/logging"
+	"github.com/owncloud/ocis/v2/services/audit/pkg/server/debug"
 	svc "github.com/owncloud/ocis/v2/services/audit/pkg/service"
 	"github.com/owncloud/ocis/v2/services/audit/pkg/types"
-	"github.com/urfave/cli/v2"
 )
 
 // Server is the entrypoint for the server command.
@@ -57,20 +56,18 @@ func Server(cfg *config.Config) *cli.Command {
 			})
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/audit/pkg/server/debug/option.go b/services/audit/pkg/server/debug/option.go
new file mode 100644
index 00000000000..9449006241f
--- /dev/null
+++ b/services/audit/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/audit/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/audit/pkg/server/debug/server.go b/services/audit/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/audit/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/auth-app/pkg/command/server.go b/services/auth-app/pkg/command/server.go
index f70aa4e8c95..00b75288776 100644
--- a/services/auth-app/pkg/command/server.go
+++ b/services/auth-app/pkg/command/server.go
@@ -82,6 +82,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/auth-app/pkg/server/debug/server.go b/services/auth-app/pkg/server/debug/server.go
index b87b7e52f11..46264bd66b9 100644
--- a/services/auth-app/pkg/server/debug/server.go
+++ b/services/auth-app/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/auth-app/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, _ *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, _ *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/auth-basic/pkg/command/server.go b/services/auth-basic/pkg/command/server.go
index 084fce012ff..475f5333bf0 100644
--- a/services/auth-basic/pkg/command/server.go
+++ b/services/auth-basic/pkg/command/server.go
@@ -87,6 +87,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/auth-basic/pkg/server/debug/server.go b/services/auth-basic/pkg/server/debug/server.go
index 18b2b02df9b..46264bd66b9 100644
--- a/services/auth-basic/pkg/server/debug/server.go
+++ b/services/auth-basic/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/auth-basic/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/auth-bearer/pkg/command/server.go b/services/auth-bearer/pkg/command/server.go
index 00652d312f3..76877780e9f 100644
--- a/services/auth-bearer/pkg/command/server.go
+++ b/services/auth-bearer/pkg/command/server.go
@@ -74,6 +74,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/auth-bearer/pkg/server/debug/server.go b/services/auth-bearer/pkg/server/debug/server.go
index fb65e4e169e..46264bd66b9 100644
--- a/services/auth-bearer/pkg/server/debug/server.go
+++ b/services/auth-bearer/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/auth-bearer/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/auth-machine/pkg/command/server.go b/services/auth-machine/pkg/command/server.go
index d90e68b7630..06a315d1dea 100644
--- a/services/auth-machine/pkg/command/server.go
+++ b/services/auth-machine/pkg/command/server.go
@@ -74,6 +74,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/auth-machine/pkg/server/debug/server.go b/services/auth-machine/pkg/server/debug/server.go
index 4f7323733a5..46264bd66b9 100644
--- a/services/auth-machine/pkg/server/debug/server.go
+++ b/services/auth-machine/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/auth-machine/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/auth-service/pkg/command/server.go b/services/auth-service/pkg/command/server.go
index 2f013c82959..35816e7806b 100644
--- a/services/auth-service/pkg/command/server.go
+++ b/services/auth-service/pkg/command/server.go
@@ -75,6 +75,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/auth-service/pkg/server/debug/server.go b/services/auth-service/pkg/server/debug/server.go
index d4616cb0f6e..46264bd66b9 100644
--- a/services/auth-service/pkg/server/debug/server.go
+++ b/services/auth-service/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/auth-service/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/clientlog/pkg/command/server.go b/services/clientlog/pkg/command/server.go
index 80261be3d32..b2194f792b2 100644
--- a/services/clientlog/pkg/command/server.go
+++ b/services/clientlog/pkg/command/server.go
@@ -8,18 +8,18 @@ import (
 	"github.com/cs3org/reva/v2/pkg/events/stream"
 	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/registry"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/clientlog/pkg/config"
 	"github.com/owncloud/ocis/v2/services/clientlog/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/clientlog/pkg/logging"
 	"github.com/owncloud/ocis/v2/services/clientlog/pkg/metrics"
+	"github.com/owncloud/ocis/v2/services/clientlog/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/clientlog/pkg/service"
-	"github.com/urfave/cli/v2"
 )
 
 // all events we care about
@@ -116,20 +116,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/clientlog/pkg/server/debug/option.go b/services/clientlog/pkg/server/debug/option.go
new file mode 100644
index 00000000000..1dafbb244ff
--- /dev/null
+++ b/services/clientlog/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/clientlog/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/clientlog/pkg/server/debug/server.go b/services/clientlog/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/clientlog/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/collaboration/pkg/server/debug/server.go b/services/collaboration/pkg/server/debug/server.go
index 89de713708b..ce5e8f02014 100644
--- a/services/collaboration/pkg/server/debug/server.go
+++ b/services/collaboration/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name+"."+options.Config.App.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/eventhistory/pkg/command/server.go b/services/eventhistory/pkg/command/server.go
index 1c9146aa756..7107f899756 100644
--- a/services/eventhistory/pkg/command/server.go
+++ b/services/eventhistory/pkg/command/server.go
@@ -7,9 +7,10 @@ import (
 	"github.com/cs3org/reva/v2/pkg/events/stream"
 	"github.com/cs3org/reva/v2/pkg/store"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+	microstore "go-micro.dev/v4/store"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
@@ -17,9 +18,8 @@ import (
 	"github.com/owncloud/ocis/v2/services/eventhistory/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/eventhistory/pkg/logging"
 	"github.com/owncloud/ocis/v2/services/eventhistory/pkg/metrics"
+	"github.com/owncloud/ocis/v2/services/eventhistory/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/eventhistory/pkg/server/grpc"
-	"github.com/urfave/cli/v2"
-	microstore "go-micro.dev/v4/store"
 )
 
 // Server is the entrypoint for the server command.
@@ -93,20 +93,18 @@ func Server(cfg *config.Config) *cli.Command {
 			})
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/eventhistory/pkg/server/debug/option.go b/services/eventhistory/pkg/server/debug/option.go
new file mode 100644
index 00000000000..a3966b315d1
--- /dev/null
+++ b/services/eventhistory/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/eventhistory/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/eventhistory/pkg/server/debug/server.go b/services/eventhistory/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/eventhistory/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/frontend/pkg/command/server.go b/services/frontend/pkg/command/server.go
index cd22a4be7f1..8f936935f34 100644
--- a/services/frontend/pkg/command/server.go
+++ b/services/frontend/pkg/command/server.go
@@ -78,6 +78,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/frontend/pkg/server/debug/server.go b/services/frontend/pkg/server/debug/server.go
index 4c813dc4fe6..46264bd66b9 100644
--- a/services/frontend/pkg/server/debug/server.go
+++ b/services/frontend/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/frontend/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/gateway/pkg/command/server.go b/services/gateway/pkg/command/server.go
index 01b2742599c..bafbf7cd828 100644
--- a/services/gateway/pkg/command/server.go
+++ b/services/gateway/pkg/command/server.go
@@ -75,9 +75,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
-				logger.Info().
-					Str("server", cfg.Service.Name).
-					Msg("Shutting down debug erver")
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/gateway/pkg/server/debug/server.go b/services/gateway/pkg/server/debug/server.go
index 18ad6b6f40b..46264bd66b9 100644
--- a/services/gateway/pkg/server/debug/server.go
+++ b/services/gateway/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/gateway/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/graph/pkg/server/debug/server.go b/services/graph/pkg/server/debug/server.go
index 314ef1b783d..85136a94de8 100644
--- a/services/graph/pkg/server/debug/server.go
+++ b/services/graph/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/graph/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,39 +25,7 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/groups/pkg/command/server.go b/services/groups/pkg/command/server.go
index cdd3db0ec2b..f79bc953e13 100644
--- a/services/groups/pkg/command/server.go
+++ b/services/groups/pkg/command/server.go
@@ -87,6 +87,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/groups/pkg/server/debug/server.go b/services/groups/pkg/server/debug/server.go
index bf0fe346a0f..46264bd66b9 100644
--- a/services/groups/pkg/server/debug/server.go
+++ b/services/groups/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/groups/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/idm/pkg/command/server.go b/services/idm/pkg/command/server.go
index 1c691b46835..19a3f6d9e6d 100644
--- a/services/idm/pkg/command/server.go
+++ b/services/idm/pkg/command/server.go
@@ -14,17 +14,16 @@ import (
 	"github.com/libregraph/idm/pkg/ldbbolt"
 	"github.com/libregraph/idm/server"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
 	pkgcrypto "github.com/owncloud/ocis/v2/ocis-pkg/crypto"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/idm"
 	"github.com/owncloud/ocis/v2/services/idm/pkg/config"
 	"github.com/owncloud/ocis/v2/services/idm/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/idm/pkg/logging"
-	"github.com/urfave/cli/v2"
+	"github.com/owncloud/ocis/v2/services/idm/pkg/server/debug"
 )
 
 // Server is the entrypoint for the server command.
@@ -94,20 +93,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/idm/pkg/server/debug/server.go b/services/idm/pkg/server/debug/server.go
index 9ac1972d456..85136a94de8 100644
--- a/services/idm/pkg/server/debug/server.go
+++ b/services/idm/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/idm/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,39 +25,7 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/idp/pkg/command/server.go b/services/idp/pkg/command/server.go
index 02bf30eaa0f..9c12ac619f0 100644
--- a/services/idp/pkg/command/server.go
+++ b/services/idp/pkg/command/server.go
@@ -36,7 +36,10 @@ func Server(cfg *config.Config) *cli.Command {
 		Usage:    fmt.Sprintf("start the %s service without runtime (unsupervised mode)", cfg.Service.Name),
 		Category: "server",
 		Before: func(c *cli.Context) error {
-			configlog.ReturnFatal(parser.ParseConfig(cfg))
+			err := configlog.ReturnFatal(parser.ParseConfig(cfg))
+			if err != nil {
+				return err
+			}
 
 			if cfg.IDP.EncryptionSecretFile != "" {
 				if err := ensureEncryptionSecretExists(cfg.IDP.EncryptionSecretFile); err != nil {
@@ -94,7 +97,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server, err := debug.Server(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
 					debug.Context(ctx),
 					debug.Config(cfg),
@@ -104,8 +107,8 @@ func Server(cfg *config.Config) *cli.Command {
 					return err
 				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/idp/pkg/server/debug/server.go b/services/idp/pkg/server/debug/server.go
index f236bc69af4..9d733267855 100644
--- a/services/idp/pkg/server/debug/server.go
+++ b/services/idp/pkg/server/debug/server.go
@@ -1,21 +1,36 @@
 package debug
 
 import (
-	"io"
+	"context"
 	"net/http"
 	"net/url"
 
-	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
-	"github.com/owncloud/ocis/v2/ocis-pkg/shared"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/idp/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger).
+			WithCheck("tcp-check", func(ctx context.Context) error {
+				tcpURL := options.Config.Ldap.URI
+				u, err := url.Parse(options.Config.Ldap.URI)
+				if err != nil {
+					return err
+				}
+				if u.Host != "" {
+					tcpURL = u.Host
+				}
+
+				return handlers.NewTCPCheck(tcpURL)(ctx)
+			}),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -24,47 +39,7 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config, options.Logger)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config, l log.Logger) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		targetHost, err := url.Parse(cfg.Ldap.URI)
-		if err != nil {
-			l.Fatal().Err(err).Str("uri", cfg.Ldap.URI).Msg("invalid LDAP URI")
-		}
-		err = shared.RunChecklist(shared.TCPConnect(targetHost.Host))
-		retVal := http.StatusOK
-		if err != nil {
-			l.Error().Err(err).Msg("Healtcheck failed")
-			retVal = http.StatusInternalServerError
-		}
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(retVal)
-
-		_, err = io.WriteString(w, http.StatusText(retVal))
-		if err != nil {
-			l.Fatal().Err(err).Msg("Could not write health check body")
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-		// if we can call this function, a http(200) is a valid response as
-		// there is nothing we can check at this point for IDP
-		// if there is a mishap when initializing, there is a minimal (talking ms or ns window)
-		// timeframe where this code is callable
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/invitations/pkg/command/server.go b/services/invitations/pkg/command/server.go
index 0b2b358cda6..24f00038049 100644
--- a/services/invitations/pkg/command/server.go
+++ b/services/invitations/pkg/command/server.go
@@ -87,7 +87,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server, err := debug.Server(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
 					debug.Context(ctx),
 					debug.Config(cfg),
@@ -97,9 +97,8 @@ func Server(cfg *config.Config) *cli.Command {
 					return err
 				}
 
-				gr.Add(server.ListenAndServe, func(err error) {
-					logger.Error().Err(err)
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/invitations/pkg/server/debug/server.go b/services/invitations/pkg/server/debug/server.go
index 663e3c45d3d..e6d7c3b0765 100644
--- a/services/invitations/pkg/server/debug/server.go
+++ b/services/invitations/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/invitations/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/nats/pkg/command/server.go b/services/nats/pkg/command/server.go
index 983909d8c67..c5401b2db98 100644
--- a/services/nats/pkg/command/server.go
+++ b/services/nats/pkg/command/server.go
@@ -7,16 +7,15 @@ import (
 
 	"github.com/oklog/run"
 
+	"github.com/urfave/cli/v2"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
 	pkgcrypto "github.com/owncloud/ocis/v2/ocis-pkg/crypto"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/nats/pkg/config"
 	"github.com/owncloud/ocis/v2/services/nats/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/nats/pkg/logging"
+	"github.com/owncloud/ocis/v2/services/nats/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/nats/pkg/server/nats"
-	"github.com/urfave/cli/v2"
 )
 
 // Server is the entrypoint for the server command.
@@ -37,20 +36,18 @@ func Server(cfg *config.Config) *cli.Command {
 			defer cancel()
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/nats/pkg/server/debug/option.go b/services/nats/pkg/server/debug/option.go
new file mode 100644
index 00000000000..977b85f3b9c
--- /dev/null
+++ b/services/nats/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/nats/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/nats/pkg/server/debug/server.go b/services/nats/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/nats/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/notifications/pkg/command/server.go b/services/notifications/pkg/command/server.go
index 25cfd126315..8aa1e1bec75 100644
--- a/services/notifications/pkg/command/server.go
+++ b/services/notifications/pkg/command/server.go
@@ -10,18 +10,17 @@ import (
 	"github.com/cs3org/reva/v2/pkg/events"
 	"github.com/cs3org/reva/v2/pkg/events/stream"
 	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/registry"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
 	"github.com/owncloud/ocis/v2/services/notifications/pkg/channels"
 	"github.com/owncloud/ocis/v2/services/notifications/pkg/config"
 	"github.com/owncloud/ocis/v2/services/notifications/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/notifications/pkg/logging"
+	"github.com/owncloud/ocis/v2/services/notifications/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/notifications/pkg/service"
 )
 
@@ -58,20 +57,18 @@ func Server(cfg *config.Config) *cli.Command {
 			defer cancel()
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/notifications/pkg/server/debug/option.go b/services/notifications/pkg/server/debug/option.go
new file mode 100644
index 00000000000..9ecb9364fef
--- /dev/null
+++ b/services/notifications/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/notifications/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/notifications/pkg/server/debug/server.go b/services/notifications/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/notifications/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/ocdav/pkg/server/debug/server.go b/services/ocdav/pkg/server/debug/server.go
index 5216000a7ac..46264bd66b9 100644
--- a/services/ocdav/pkg/server/debug/server.go
+++ b/services/ocdav/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/ocdav/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/ocm/pkg/command/server.go b/services/ocm/pkg/command/server.go
index 2e28cccedcd..7e7265b066d 100644
--- a/services/ocm/pkg/command/server.go
+++ b/services/ocm/pkg/command/server.go
@@ -75,6 +75,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/ocm/pkg/server/debug/server.go b/services/ocm/pkg/server/debug/server.go
index d97b3fde109..46264bd66b9 100644
--- a/services/ocm/pkg/server/debug/server.go
+++ b/services/ocm/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/ocm/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/ocs/pkg/server/debug/server.go b/services/ocs/pkg/server/debug/server.go
index 536c972458e..e6d7c3b0765 100644
--- a/services/ocs/pkg/server/debug/server.go
+++ b/services/ocs/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/ocs/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/policies/pkg/command/server.go b/services/policies/pkg/command/server.go
index 5719335ae21..832909400ea 100644
--- a/services/policies/pkg/command/server.go
+++ b/services/policies/pkg/command/server.go
@@ -3,14 +3,13 @@ package command
 import (
 	"context"
 	"fmt"
-	"io"
-	"net/http"
 
 	"github.com/cs3org/reva/v2/pkg/events/stream"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
@@ -18,9 +17,9 @@ import (
 	"github.com/owncloud/ocis/v2/services/policies/pkg/config"
 	"github.com/owncloud/ocis/v2/services/policies/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/policies/pkg/engine/opa"
+	"github.com/owncloud/ocis/v2/services/policies/pkg/server/debug"
 	svcEvent "github.com/owncloud/ocis/v2/services/policies/pkg/service/event"
 	svcGRPC "github.com/owncloud/ocis/v2/services/policies/pkg/service/grpc"
-	"github.com/urfave/cli/v2"
 )
 
 // Server is the entrypoint for the server command.
@@ -121,46 +120,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(
-						func(w http.ResponseWriter, r *http.Request) {
-							w.Header().Set("Content-Type", "text/plain")
-							w.WriteHeader(http.StatusOK)
-
-							// TODO: check if services are up and running
-
-							_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-							// io.WriteString should not fail but if it does, we want to know.
-							if err != nil {
-								panic(err)
-							}
-						},
-					),
-					debug.Ready(
-						func(w http.ResponseWriter, r *http.Request) {
-							w.Header().Set("Content-Type", "text/plain")
-							w.WriteHeader(http.StatusOK)
-
-							// TODO: check if services are up and running
-
-							_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-							// io.WriteString should not fail but if it does, we want to know.
-							if err != nil {
-								panic(err)
-							}
-						},
-					),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/policies/pkg/server/debug/option.go b/services/policies/pkg/server/debug/option.go
new file mode 100644
index 00000000000..aaf0a8d7a86
--- /dev/null
+++ b/services/policies/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/policies/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/policies/pkg/server/debug/server.go b/services/policies/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/policies/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/postprocessing/pkg/command/server.go b/services/postprocessing/pkg/command/server.go
index 6715a914634..8527b71dc7b 100644
--- a/services/postprocessing/pkg/command/server.go
+++ b/services/postprocessing/pkg/command/server.go
@@ -8,16 +8,15 @@ import (
 	"github.com/cs3org/reva/v2/pkg/events/stream"
 	"github.com/cs3org/reva/v2/pkg/store"
 	"github.com/oklog/run"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/urfave/cli/v2"
+	microstore "go-micro.dev/v4/store"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/postprocessing/pkg/config"
 	"github.com/owncloud/ocis/v2/services/postprocessing/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/postprocessing/pkg/logging"
+	"github.com/owncloud/ocis/v2/services/postprocessing/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/postprocessing/pkg/service"
-	"github.com/urfave/cli/v2"
-	microstore "go-micro.dev/v4/store"
 )
 
 // Server is the entrypoint for the server command.
@@ -86,20 +85,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/postprocessing/pkg/server/debug/option.go b/services/postprocessing/pkg/server/debug/option.go
new file mode 100644
index 00000000000..da002867f78
--- /dev/null
+++ b/services/postprocessing/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/postprocessing/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/postprocessing/pkg/server/debug/server.go b/services/postprocessing/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/postprocessing/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/proxy/pkg/command/server.go b/services/proxy/pkg/command/server.go
index ae17b743a1b..7dd1673be86 100644
--- a/services/proxy/pkg/command/server.go
+++ b/services/proxy/pkg/command/server.go
@@ -214,7 +214,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server, err := debug.Server(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
 					debug.Context(ctx),
 					debug.Config(cfg),
@@ -224,8 +224,8 @@ func Server(cfg *config.Config) *cli.Command {
 					return err
 				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/proxy/pkg/server/debug/server.go b/services/proxy/pkg/server/debug/server.go
index ae2a3349b0f..f7368549624 100644
--- a/services/proxy/pkg/server/debug/server.go
+++ b/services/proxy/pkg/server/debug/server.go
@@ -2,10 +2,11 @@ package debug
 
 import (
 	"encoding/json"
-	"io"
 	"net/http"
 
-	masker "github.com/ggwhite/go-masker"
+	"github.com/ggwhite/go-masker"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
@@ -15,6 +16,12 @@ import (
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	var configDumpFunc http.HandlerFunc = configDump(options.Config)
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -23,44 +30,12 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
-		debug.ConfigDump(configDump(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+		debug.ConfigDump(configDumpFunc),
 	), nil
 }
 
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
 // configDump implements the config dump
 func configDump(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
diff --git a/services/search/pkg/command/server.go b/services/search/pkg/command/server.go
index 1e823e42e4e..f098602a67b 100644
--- a/services/search/pkg/command/server.go
+++ b/services/search/pkg/command/server.go
@@ -70,7 +70,7 @@ func Server(cfg *config.Config) *cli.Command {
 				cancel()
 			})
 
-			server, err := debug.Server(
+			debugServer, err := debug.Server(
 				debug.Logger(logger),
 				debug.Context(ctx),
 				debug.Config(cfg),
@@ -80,8 +80,8 @@ func Server(cfg *config.Config) *cli.Command {
 				return err
 			}
 
-			gr.Add(server.ListenAndServe, func(_ error) {
-				_ = server.Shutdown(ctx)
+			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/search/pkg/server/debug/server.go b/services/search/pkg/server/debug/server.go
index e1ac53041da..85136a94de8 100644
--- a/services/search/pkg/server/debug/server.go
+++ b/services/search/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/search/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,39 +25,7 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/settings/pkg/command/server.go b/services/settings/pkg/command/server.go
index 5b11f00a56e..1e442ab6fd2 100644
--- a/services/settings/pkg/command/server.go
+++ b/services/settings/pkg/command/server.go
@@ -94,7 +94,11 @@ func Server(cfg *config.Config) *cli.Command {
 			})
 
 			// prepare a debug server and add it to the group run.
-			debugServer, err := debug.Server(debug.Logger(logger), debug.Context(ctx), debug.Config(cfg))
+			debugServer, err := debug.Server(
+				debug.Logger(logger),
+				debug.Context(ctx),
+				debug.Config(cfg),
+			)
 			if err != nil {
 				logger.Error().Err(err).Str("server", "debug").Msg("Failed to initialize server")
 				return err
diff --git a/services/settings/pkg/server/debug/server.go b/services/settings/pkg/server/debug/server.go
index 8b667f094fd..e6d7c3b0765 100644
--- a/services/settings/pkg/server/debug/server.go
+++ b/services/settings/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/settings/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/sharing/pkg/server/debug/server.go b/services/sharing/pkg/server/debug/server.go
index 818cf6012b8..46264bd66b9 100644
--- a/services/sharing/pkg/server/debug/server.go
+++ b/services/sharing/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/sharing/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/sse/pkg/command/server.go b/services/sse/pkg/command/server.go
index 06491d29062..722eb3970db 100644
--- a/services/sse/pkg/command/server.go
+++ b/services/sse/pkg/command/server.go
@@ -10,13 +10,11 @@ import (
 	"github.com/urfave/cli/v2"
 
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
-	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/sse/pkg/config"
 	"github.com/owncloud/ocis/v2/services/sse/pkg/config/parser"
+	"github.com/owncloud/ocis/v2/services/sse/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/sse/pkg/server/http"
 )
 
@@ -77,20 +75,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/sse/pkg/server/debug/option.go b/services/sse/pkg/server/debug/option.go
new file mode 100644
index 00000000000..03d14d82f64
--- /dev/null
+++ b/services/sse/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/sse/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/sse/pkg/server/debug/server.go b/services/sse/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/sse/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/storage-publiclink/pkg/command/server.go b/services/storage-publiclink/pkg/command/server.go
index 184254cb9ff..d15dac8ceca 100644
--- a/services/storage-publiclink/pkg/command/server.go
+++ b/services/storage-publiclink/pkg/command/server.go
@@ -74,6 +74,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/storage-publiclink/pkg/server/debug/server.go b/services/storage-publiclink/pkg/server/debug/server.go
index 4cf599ceddf..46264bd66b9 100644
--- a/services/storage-publiclink/pkg/server/debug/server.go
+++ b/services/storage-publiclink/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/storage-publiclink/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/storage-shares/pkg/command/server.go b/services/storage-shares/pkg/command/server.go
index bdeabf0e2d8..41757ff57d9 100644
--- a/services/storage-shares/pkg/command/server.go
+++ b/services/storage-shares/pkg/command/server.go
@@ -74,6 +74,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/storage-shares/pkg/server/debug/server.go b/services/storage-shares/pkg/server/debug/server.go
index 2f301be8be9..46264bd66b9 100644
--- a/services/storage-shares/pkg/server/debug/server.go
+++ b/services/storage-shares/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/storage-shares/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/storage-system/pkg/command/server.go b/services/storage-system/pkg/command/server.go
index 5195280e416..2b50a59a0e9 100644
--- a/services/storage-system/pkg/command/server.go
+++ b/services/storage-system/pkg/command/server.go
@@ -74,6 +74,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/storage-system/pkg/server/debug/server.go b/services/storage-system/pkg/server/debug/server.go
index b5bc0977b3c..46264bd66b9 100644
--- a/services/storage-system/pkg/server/debug/server.go
+++ b/services/storage-system/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/storage-system/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/storage-users/pkg/command/server.go b/services/storage-users/pkg/command/server.go
index df7fca8a4b6..f88ed590c9b 100644
--- a/services/storage-users/pkg/command/server.go
+++ b/services/storage-users/pkg/command/server.go
@@ -76,15 +76,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(err error) {
-				logger.Error().Err(err).Str("server", cfg.Service.Name).
-					Msg("Shutting down debug server")
-				if err := debugServer.Shutdown(context.Background()); err != nil {
-					logger.Error().
-						Err(err).
-						Str("server", cfg.Service.Name).
-						Msg("Error during debug server shutdown")
-				}
-
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/storage-users/pkg/server/debug/server.go b/services/storage-users/pkg/server/debug/server.go
index 268324919cd..13fa273ee55 100644
--- a/services/storage-users/pkg/server/debug/server.go
+++ b/services/storage-users/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/storage-users/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Context(options.Context),
@@ -22,43 +26,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/thumbnails/pkg/command/server.go b/services/thumbnails/pkg/command/server.go
index cc671f74f25..4ad5ae0fdd7 100644
--- a/services/thumbnails/pkg/command/server.go
+++ b/services/thumbnails/pkg/command/server.go
@@ -74,6 +74,7 @@ func Server(cfg *config.Config) *cli.Command {
 			server, err := debug.Server(
 				debug.Logger(logger),
 				debug.Config(cfg),
+				debug.Context(ctx),
 			)
 			if err != nil {
 				logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
diff --git a/services/thumbnails/pkg/server/debug/option.go b/services/thumbnails/pkg/server/debug/option.go
index 534a47f1ccd..fdc0fe6bc8e 100644
--- a/services/thumbnails/pkg/server/debug/option.go
+++ b/services/thumbnails/pkg/server/debug/option.go
@@ -1,6 +1,8 @@
 package debug
 
 import (
+	"context"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
 )
@@ -13,6 +15,7 @@ type Options struct {
 	Name    string
 	Address string
 	Logger  log.Logger
+	Context context.Context
 	Config  *config.Config
 }
 
@@ -34,6 +37,13 @@ func Logger(val log.Logger) Option {
 	}
 }
 
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
 // Config provides a function to set the config option.
 func Config(val *config.Config) Option {
 	return func(o *Options) {
diff --git a/services/thumbnails/pkg/server/debug/server.go b/services/thumbnails/pkg/server/debug/server.go
index 914167fac8c..e6d7c3b0765 100644
--- a/services/thumbnails/pkg/server/debug/server.go
+++ b/services/thumbnails/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, _ *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, _ *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/userlog/pkg/command/server.go b/services/userlog/pkg/command/server.go
index 71a52ca7fac..566c5f76e7c 100644
--- a/services/userlog/pkg/command/server.go
+++ b/services/userlog/pkg/command/server.go
@@ -9,10 +9,11 @@ import (
 	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
 	"github.com/cs3org/reva/v2/pkg/store"
 	"github.com/oklog/run"
+	"github.com/urfave/cli/v2"
+	microstore "go-micro.dev/v4/store"
+
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
-	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/registry"
-	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
@@ -22,9 +23,8 @@ import (
 	"github.com/owncloud/ocis/v2/services/userlog/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/userlog/pkg/logging"
 	"github.com/owncloud/ocis/v2/services/userlog/pkg/metrics"
+	"github.com/owncloud/ocis/v2/services/userlog/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/userlog/pkg/server/http"
-	"github.com/urfave/cli/v2"
-	microstore "go-micro.dev/v4/store"
 )
 
 // all events we care about
@@ -144,20 +144,18 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server := debug.NewService(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
-					debug.Name(cfg.Service.Name),
-					debug.Version(version.GetString()),
-					debug.Address(cfg.Debug.Addr),
-					debug.Token(cfg.Debug.Token),
-					debug.Pprof(cfg.Debug.Pprof),
-					debug.Zpages(cfg.Debug.Zpages),
-					debug.Health(handlers.Health),
-					debug.Ready(handlers.Ready),
+					debug.Context(ctx),
+					debug.Config(cfg),
 				)
+				if err != nil {
+					logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
+					return err
+				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/userlog/pkg/server/debug/option.go b/services/userlog/pkg/server/debug/option.go
new file mode 100644
index 00000000000..6e3607ac636
--- /dev/null
+++ b/services/userlog/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/services/userlog/pkg/config"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/services/userlog/pkg/server/debug/server.go b/services/userlog/pkg/server/debug/server.go
new file mode 100644
index 00000000000..85136a94de8
--- /dev/null
+++ b/services/userlog/pkg/server/debug/server.go
@@ -0,0 +1,31 @@
+package debug
+
+import (
+	"net/http"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/v2/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.GetString()),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
+	), nil
+}
diff --git a/services/users/pkg/command/server.go b/services/users/pkg/command/server.go
index 95a899873da..aed4caa147c 100644
--- a/services/users/pkg/command/server.go
+++ b/services/users/pkg/command/server.go
@@ -87,6 +87,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			gr.Add(debugServer.ListenAndServe, func(_ error) {
+				_ = debugServer.Shutdown(ctx)
 				cancel()
 			})
 
diff --git a/services/users/pkg/server/debug/server.go b/services/users/pkg/server/debug/server.go
index b10bacdc204..46264bd66b9 100644
--- a/services/users/pkg/server/debug/server.go
+++ b/services/users/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/users/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		//debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		//debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		//debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		//debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/web/pkg/command/server.go b/services/web/pkg/command/server.go
index 5ba91343195..73ceba8cce1 100644
--- a/services/web/pkg/command/server.go
+++ b/services/web/pkg/command/server.go
@@ -93,7 +93,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server, err := debug.Server(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
 					debug.Context(ctx),
 					debug.Config(cfg),
@@ -103,8 +103,8 @@ func Server(cfg *config.Config) *cli.Command {
 					return err
 				}
 
-				gr.Add(server.ListenAndServe, func(_ error) {
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(_ error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/web/pkg/server/debug/server.go b/services/web/pkg/server/debug/server.go
index 0ffe3259c0a..f5c6bd5a9b8 100644
--- a/services/web/pkg/server/debug/server.go
+++ b/services/web/pkg/server/debug/server.go
@@ -1,18 +1,38 @@
 package debug
 
 import (
-	"io"
+	"context"
+	"fmt"
+	"net"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/web/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger).WithCheck("web reachability", func(ctx context.Context) error {
+			conn, err := net.Dial("tcp", options.Config.HTTP.Addr)
+			defer func(conn net.Conn) {
+				err := conn.Close()
+				if err != nil {
+					return
+				}
+			}(conn)
+			if err != nil {
+				return fmt.Errorf("could not connect to web server: %v", err)
+			}
+
+			return nil
+		}),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,39 +41,7 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 	), nil
 }
-
-// health implements the health check.
-func health(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, _ *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, _ *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/webdav/pkg/command/server.go b/services/webdav/pkg/command/server.go
index d7ed386242d..869b80f0ca1 100644
--- a/services/webdav/pkg/command/server.go
+++ b/services/webdav/pkg/command/server.go
@@ -82,7 +82,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server, err := debug.Server(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
 					debug.Context(ctx),
 					debug.Config(cfg),
@@ -93,9 +93,8 @@ func Server(cfg *config.Config) *cli.Command {
 					return err
 				}
 
-				gr.Add(server.ListenAndServe, func(err error) {
-					logger.Error().Err(err)
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(err error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/webdav/pkg/server/debug/server.go b/services/webdav/pkg/server/debug/server.go
index 8c4bd1c6c35..e6d7c3b0765 100644
--- a/services/webdav/pkg/server/debug/server.go
+++ b/services/webdav/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/webdav/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
diff --git a/services/webfinger/pkg/command/server.go b/services/webfinger/pkg/command/server.go
index 0ba9cbe1298..0088349687d 100644
--- a/services/webfinger/pkg/command/server.go
+++ b/services/webfinger/pkg/command/server.go
@@ -95,7 +95,7 @@ func Server(cfg *config.Config) *cli.Command {
 			}
 
 			{
-				server, err := debug.Server(
+				debugServer, err := debug.Server(
 					debug.Logger(logger),
 					debug.Context(ctx),
 					debug.Config(cfg),
@@ -106,9 +106,8 @@ func Server(cfg *config.Config) *cli.Command {
 					return err
 				}
 
-				gr.Add(server.ListenAndServe, func(err error) {
-					logger.Error().Err(err)
-					_ = server.Shutdown(ctx)
+				gr.Add(debugServer.ListenAndServe, func(err error) {
+					_ = debugServer.Shutdown(ctx)
 					cancel()
 				})
 			}
diff --git a/services/webfinger/pkg/server/debug/server.go b/services/webfinger/pkg/server/debug/server.go
index 2701befb13f..e6d7c3b0765 100644
--- a/services/webfinger/pkg/server/debug/server.go
+++ b/services/webfinger/pkg/server/debug/server.go
@@ -1,18 +1,22 @@
 package debug
 
 import (
-	"io"
 	"net/http"
 
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
 	"github.com/owncloud/ocis/v2/ocis-pkg/service/debug"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
-	"github.com/owncloud/ocis/v2/services/webfinger/pkg/config"
 )
 
 // Server initializes the debug service and server.
 func Server(opts ...Option) (*http.Server, error) {
 	options := newOptions(opts...)
 
+	checkHandler := handlers.NewCheckHandler(
+		handlers.NewCheckHandlerConfiguration().
+			WithLogger(options.Logger),
+	)
+
 	return debug.NewService(
 		debug.Logger(options.Logger),
 		debug.Name(options.Config.Service.Name),
@@ -21,43 +25,11 @@ func Server(opts ...Option) (*http.Server, error) {
 		debug.Token(options.Config.Debug.Token),
 		debug.Pprof(options.Config.Debug.Pprof),
 		debug.Zpages(options.Config.Debug.Zpages),
-		debug.Health(health(options.Config)),
-		debug.Ready(ready(options.Config)),
+		debug.Health(checkHandler),
+		debug.Ready(checkHandler),
 		debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
 		debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
 		debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
 		debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 	), nil
 }
-
-// health implements the health check.
-func health(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}
-
-// ready implements the ready check.
-func ready(_ *config.Config) func(http.ResponseWriter, *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-
-		// TODO: check if services are up and running
-
-		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
-		// io.WriteString should not fail but if it does, we want to know.
-		if err != nil {
-			panic(err)
-		}
-	}
-}


Test patch:
diff --git a/ocis-pkg/handlers/checker_test.go b/ocis-pkg/handlers/checker_test.go
new file mode 100644
index 00000000000..0c5cadb28d6
--- /dev/null
+++ b/ocis-pkg/handlers/checker_test.go
@@ -0,0 +1,29 @@
+package handlers_test
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	"github.com/owncloud/ocis/v2/ocis-pkg/handlers"
+)
+
+func TestCheckHandler_AddCheck(t *testing.T) {
+	c := handlers.NewCheckHandlerConfiguration().WithCheck("shared-check", func(ctx context.Context) error { return nil })
+
+	t.Run("configured checks are unique once added", func(t *testing.T) {
+		defer func() {
+			if r := recover(); r != nil {
+				t.Errorf("checks should be unique, got %v", r)
+			}
+		}()
+
+		h1 := handlers.NewCheckHandler(c)
+		h1.AddCheck("check-with-same-name", func(ctx context.Context) error { return nil })
+
+		h2 := handlers.NewCheckHandler(c)
+		h2.AddCheck("check-with-same-name", func(ctx context.Context) error { return nil })
+
+		fmt.Print(1)
+	})
+}