Installation as a Web Server for Linux
This guide describes how to run CODESYS 4 as a server on Linux.
Compatibility
CODESYS 4 on Linux is officially supported only for Debian at this time. It is possible that the package can also be made to run on other Debian-based distributions, such as Ubuntu, Kubuntu, etc. However, support for this can only be offered to a limited degree.
Preliminary remarks
Fundamentals of Linux system administration
User management on Linux (PAM, LDAP, IPA, etc.)
Package management on Debian
Knowledge of TLS certificate management and, if possible, the respective infrastructure
Possibly knowledge of Docker, nginx, and other server technologies
HTTPS/TLS
CODESYS 4 uses browser APIs which are available only in a secure context. This is always the case when access is via localhost.
As soon as you want to make CODESYS 4 as a server accessible to other computers on the network, however, it is absolutely necessary for communication to take place via HTTPS, otherwise the application will not work properly.
Because CODESYS 4 itself does not yet support communication via HTTPS, you will need to set up an upstream proxy to do this. For more information, read the entire section Setting up an upstream TLS reverse proxy carefully.
Runtime and gateway
The Linux packages from CODESYS 4 do not currently include a CODESYS Gateway or a CODESYS Runtime.
You can find the corresponding downloads in the CODESYS Store.
Make sure that you configure the communication settings (gateway) in your project so that you can access the controller from the server.
Users who work on the server can only access it with CODESYS gateways and controllers which can be reached by the server. Make sure that the server has access to the required gateways, or make a local gateway available directly on the server.
Preparation: Creating user accounts
By default, the user management of the CODESYS 4 server is based on the user management of the Debian system. Every ordinary Linux user who is a member of the codesys-4 group can log in to the CODESYS 4 server by default. However, you can also start the server with the option --login-groups=first,second,third to specify one or more other groups which should be able to log in instead.
Create the
codesys-4group.This is necessary only one time and is done automatically during the installation of the Debian package.
Specify your own group here if you want to use a different group.
sudo addgroup codesys-4
Create the new user
User1if it does not already exist.(The prompt for user information such as
FullName,Room Number, etc. can simply be skipped by leaving them blank.)sudo adduser User1
Add
User1to thecodesys-4group. Assign the user to a different group if you are using your own group.(This gives that user permission to log in to the server.)
sudo adduser User1 codesys-4
You can create any number of users. All users who can log in using a password and are members of the codesys-4 group can log in to CODESYS 4.
Operation as a server via systemd
CODESYS 4 as a server must be run under a dedicated system user.
Preparation
CODESYS 4 must be installed on the web server. To do this, install CODESYS 4 according to the guide in the chapter Installation as a Desktop Application for Linux (up to and including the section "Installing a Debian package").
Create a dedicated system user for testing purposes.
> sudo useradd --system --create-home c4-server
In the directory
/etc/systemd/system/codesys-4.service, configure theService Unitfile forsystemd[Unit] Description=CODESYS 4 Server [Service] Type=exec WorkingDirectory=/opt/codesys-4/ ExecStart=/opt/codesys-4/c4-server --port 8080 Restart=always # Restart service after 10 seconds if the dotnet service crashes: RestartSec=10 KillSignal=SIGINT SyslogIdentifier=codesys-4-server User=c4-server Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false [Install] WantedBy=multi-user.target
Start the service via
systemd.$> sudo systemctl start codesys-4
The service will be available via HTTP on
localhoston port 8080.
Operation as a server via Docker
Not a standard Docker image
CODESYS 4 is not currently distributed as a Docker image. As a result, there is no official Docker image intended for the productive use of CODESYS 4.
You can, however, build your own Docker image. The steps for this are described later in this section.
Prior knowledge and support
To correctly set up this use case, basic knowledge of Docker is absolutely required. No support can be provided for the basic use of Docker.
# Official ASP.NET 8.0 runtime base image FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /opt/codesys-4 # The default port is 8080 EXPOSE 8080 # We have to be root to install the package, switch back to app after USER root # Install the Debian package for CODESYS 4. # We set ACCEPT_CODESYS_EULA=true to skip the interactive prompt to accept the EULA during package installation. # Building and executing this Dockerfile therefore means you accept the terms and condition of the CODESYS Engineering EULA! RUN --mount=type=bind,source=output/,target=/tmp/output/ <<EOF ACCEPT_CODESYS_EULA=true dpkg -i /tmp/output/codesys-4*.deb EOF # The server should run with the unprivileged system user "app", see # https://learn.microsoft.com/en-us/dotnet/core/compatibility/containers/8.0/app-user # For security reasons, c4-server will refuse to start as root. USER app:app ENTRYPOINT ["/opt/codesys-4/c4-server"]
To build the image, you first need to download the Debian package for CODESYS 4 and save it to the output/ subfolder where the Dockerfile is located. Then you can build the image as usual using the docker buildx build command.
When starting the image in a container, be aware that only the users that exist in the container and are members of the codesys-4 group can log in to the server (compare with the chapter Preparation: Creating user accounts).
Users must have access to suitable mechanisms within the container, for example PAM. The home directories must as far as possible be mounted as persistent volumes in the container. Deviating group definitions via the --login-groups option can either be specified in the Dockerfile as an argument in the ENTRYPOINT definition or be passed as an argument when the container is started.
For testing purposes, you can synchronize the existing users on the host in the container immediately after starting it, as shown in the docker-test-example.sh script:
(Of course, you will need to adapt the script to your specific conditions, such as your tag identifiers and your own Docker registry.)
# This script is used to start our CODESYS 4 docker containers in our
# development and test environments (RasPi, WSL, Linux VM).
# It's not regarded as safe for production use!
# The name of our container
CONTAINER=codesys-4
# The repository to fetch the image from
URL="dockerhost.example.com:1234/codesys-images/codesys-4:develop"
# Stop and clean up any running container.
if docker inspect "$CONTAINER" > /dev/null 2>&1; then
echo Trying to clean up
docker stop "$CONTAINER"
docker rm "$CONTAINER"
fi
# stop and rm may fail when the container does not exist,
# but from here on, we want to abort on first error
set -e
echo Downloading "$URL"...
docker pull "$URL"
echo starting image...
# Starting the docker image.
# We mount the /home folder. We listen on port 8080.
# The option "--add-host host.docker.internal:host-gateway" allows us to access
# a CODESYS gateway running on the host machine via the hostname
# "host.docker.internal" from within the container.
docker run --restart=unless-stopped --detach \
--volume /home:/home \
-p127.0.0.1:8080:8080 \
-e CBE_PORT=8080 \
--add-host host.docker.internal:host-gateway \
--name "$CONTAINER" \
"$URL"
# output the version and build info, with some newlines, so it's easier readable.
echo -e \\n CODESYS 4 image build info: $(docker exec codesys-4 cat /opt/codesys-4/dist/version.json) \\n
# Ensure we have a home directory the app user can use, to write the C4 log files.
# The base image already contains /home/app, but it's shadowed by mounting our
# /home into the container, so we need to create the folder if it doesn't exist.
# Strictly speaking, this is only necessary once on a given host (because /home
# has been mounted from the host), but if we run it always, we can be sure that
# this script will also work on fresh machines.
docker exec --user 0 "$CONTAINER" bash -c "mkdir -v -p /home/app ; chown -v app:app /home/app ; chmod -v og-rwx /home/app"
# Synchronize the actual users into the container. We use a very hackish approach
# here, not recommended for production use, it just works for the dev environment.
# WARNING: Synchronizing will only work when:
# 1) The users do not yet exist within the container
# 2) The numeric user and group IDs are not yet occupied within the container.
# Also, it's recommended to configure sudo so it caches the password using
# timestamp-timeout, or even NOPASSWD if you want to take the risk.
# Only the groups codesys-4 and the user personal group will be synchronized.
echo synchronizing group codesys-4
getent group codesys-4| docker exec --user 0 -i "$CONTAINER" /bin/sh -c "cat >>/etc/group"
sudo getent gshadow codesys-4| docker exec --user 0 -i "$CONTAINER" /bin/sh -c "cat >>/etc/gshadow"
# get all users in group codesys-4
C4_USERS=$(getent group codesys-4| awk -F':' '{print $4}' | tr ',' ' ')
for CURRENT in $C4_USERS ; do
echo synchronizing user $CURRENT
getent passwd $CURRENT | docker exec --user 0 -i "$CONTAINER" /bin/sh -c "cat >>/etc/passwd"
sudo getent shadow $CURRENT | docker exec --user 0 -i "$CONTAINER" /bin/sh -c "cat >>/etc/shadow"
# we also need to synchronize the user specific group
getent group $CURRENT | docker exec --user 0 -i "$CONTAINER" /bin/sh -c "cat >>/etc/group"
sudo getent gshadow $CURRENT | docker exec --user 0 -i "$CONTAINER" /bin/sh -c "cat >>/etc/gshadow"
done
echo finished.Pre-positioning a TLS reverse proxy
CODESYS 4 uses browser APIs which are available only in a secure context. This is always the case when access is via localhost. As soon as CODESYS 4 as a server is accessible by other computers in the network, a TLS encryption, whose server certificate is trusted by the used browsers, must necessarily be set up.
CODESYS 4 does not currently implement TLS encryption yet. When CODESYS 4 runs behind a portal proxy, it can maintain the TLS encryption. Otherwise, a reverse proxy such as nginx can easily be pre-positioned beforehand which will maintain the TLS encryption. In particular, the proxy_set_header and proxy_cache_bypass directives are necessary so that everything works correctly (including WebSocket).
SSL certificates
For this use case, you absolutely need either a valid SSL certificate or a self-signed SSL certificate which is classified as trusted within your organization.
Consult with your IT administrator and do not attempt to classify your own certificates as trusted without prior knowledge.
If you still want to issue certificates for testing purposes and you know what you are doing, then you can follow the guide in the section Using TLS certificates for testing purposes. These certificates must never be used in production.
Nginx as a reverse proxy
The following example shows a configuration of nginx as a reverse proxy in order to maintain TLS encryption for CODESYS 4. You can save the following file at /etc/nginx/sites-available/codesys-4. You also need to adapt the paths under ssl_certificate and ssl_certificate_key to the actual locations of your certificates. After that, you can use symlink to enable the configuration under /etc/nginx/sites-enabled/ and restart nginx.
# See https://docs.microsoft.com/en-us/troubleshoot/developer/webapps/aspnetcore/practice-troubleshoot-linux/2-2-install-nginx-configure-it-reverse-proxy
# for more information.
server {
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/ssl/certs/codesys-4-certificate.crt;
ssl_certificate_key /etc/ssl/private/codesys-4.key;
#server_name _;
server_tokens off; # see https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens
location / {
rewrite ^/$ /index.html last;
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
#hsts header
add_header Strict-Transport-Security "max-age=31536000" always;
}
}
# Redirect unencrypted http access to encrypted https access.
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name _;
return 301 https://$host$request_uri;
}TLS certificates for testing purposes
Security notice
WARNING: Issuing and trusting your own certificates can pose a significant security risk. Perform the following steps only if you have permission from your IT administrator. Do not attempt to bypass any existing group policies or other security precautions to perform these steps.
For productive use, certificates from an official certification authority (CA) recognized by browsers are strongly recommended, or alternatively, certificates recognized within your company infrastructure. When in doubt, consult your IT department.
Make absolute sure to store the private key files example.key and in particular exampleca.key securely and that they are not accessible to anyone else. Anyone who gets access to these files can use them to forge any number of certificates and thereby launch a man-in-the-middle attack against you or your organization.
You can use the openssl command to generate certificates for testing purposes as shown below. Before that, in the example_cert.ext file, you will need to edit the host names for which the certificate should be valid. You should also adapt the --subj parameters in the commands according to your specific use case.
authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment extendedKeyUsage=serverAuth subjectAltName = @alt_names [alt_names] DNS.1=localhost # adjust these to your needs DNS.2=first.host.example.com DNS.3=other.host.example.com
# Generate development/testing certificates for CODESYS 4. # Add the hostnames to example_cert.ext with your favourite text editor. # Creating the CA: openssl genrsa -out exampleca.key 2048 openssl req -new -x509 -days 365 -key exampleca.key -subj "/C=ZZ/ST=Example Kingdom/L=Example City/O=Example Organization/CN=Example Test CA" -out exampleca.crt # Creating the Certificate: openssl genrsa -out example.key 2048 openssl req -new -nodes -out example.csr -key example.key -subj "/C=ZZ/ST=Example Kingdom/L=Example City/O=Example Organization/CN=Example Test Server" openssl x509 -req -days 365 -in example.csr -CA exampleca.crt -CAkey exampleca.key -out codesys-4-development-certificate.crt -extfile example_cert.ext -CAcreateserial
Important
Compatibility
With a Cygwin-based shell – for example Git bash – the openssl req command may fail. This is a known issue in OpenSSL in connection with Cygwin. For more information, see the following: https://github.com/openssl/openssl/issues/8795.
The issue should not occur when you run OpenSSL in a genuine Linux shell (also called WSL) or via the command line of CMD or PowerShell.
The root certificate exampleca.crt then needs to be registered as trusted in the respective browsers. The actual certificate codesys-4-development-certificate.crt and the respective private key example.key must be installed on the server and referenced in the server configuration. For example, nginx can be used for this purpose (see the section Pre-positioning a TLS reverse proxy.
Remember to remove the exampleca.crt certificate from the list of your trusted certificates in your browsers after the testing phase.